diff options
Diffstat (limited to 'src')
58 files changed, 24224 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ba388d3 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,43 @@ +# 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. + +INCLUDES = -I$(top_srcdir)/include +SUBDIRS = plugins + +MAINTAINERCLEANFILES = Makefile.in + +ipmitool_SOURCES = ipmitool.c ipmishell.c +ipmitool_LDADD = $(top_builddir)/lib/libipmitool.la plugins/libintf.la + +ipmievd_SOURCES = ipmievd.c +ipmievd_LDADD = $(top_builddir)/lib/libipmitool.la plugins/libintf.la + +bin_PROGRAMS = ipmitool +sbin_PROGRAMS = ipmievd diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..b3cde64 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,788 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +bin_PROGRAMS = ipmitool$(EXEEXT) +sbin_PROGRAMS = ipmievd$(EXEEXT) +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" +PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) +am_ipmievd_OBJECTS = ipmievd.$(OBJEXT) +ipmievd_OBJECTS = $(am_ipmievd_OBJECTS) +ipmievd_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la \ + plugins/libintf.la +am_ipmitool_OBJECTS = ipmitool.$(OBJEXT) ipmishell.$(OBJEXT) +ipmitool_OBJECTS = $(am_ipmitool_OBJECTS) +ipmitool_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la \ + plugins/libintf.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(ipmievd_SOURCES) $(ipmitool_SOURCES) +DIST_SOURCES = $(ipmievd_SOURCES) $(ipmitool_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +INCLUDES = -I$(top_srcdir)/include +SUBDIRS = plugins +MAINTAINERCLEANFILES = Makefile.in +ipmitool_SOURCES = ipmitool.c ipmishell.c +ipmitool_LDADD = $(top_builddir)/lib/libipmitool.la plugins/libintf.la +ipmievd_SOURCES = ipmievd.c +ipmievd_LDADD = $(top_builddir)/lib/libipmitool.la plugins/libintf.la +all: all-recursive + +.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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/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 +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +ipmievd$(EXEEXT): $(ipmievd_OBJECTS) $(ipmievd_DEPENDENCIES) $(EXTRA_ipmievd_DEPENDENCIES) + @rm -f ipmievd$(EXEEXT) + $(LINK) $(ipmievd_OBJECTS) $(ipmievd_LDADD) $(LIBS) +ipmitool$(EXEEXT): $(ipmitool_OBJECTS) $(ipmitool_DEPENDENCIES) $(EXTRA_ipmitool_DEPENDENCIES) + @rm -f ipmitool$(EXEEXT) + $(LINK) $(ipmitool_OBJECTS) $(ipmitool_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmievd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmishell.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmitool.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool \ + clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-sbinPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-sbinPROGRAMS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool clean-sbinPROGRAMS ctags \ + ctags-recursive 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-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-sbinPROGRAMS + + +# 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/src/ipmievd.c b/src/ipmievd.c new file mode 100644 index 0000000..f940579 --- /dev/null +++ b/src/ipmievd.c @@ -0,0 +1,881 @@ +/* + * 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 <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined(HAVE_SYS_IOCCOM_H) +# include <sys/ioccom.h> +#endif + +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif + +#ifndef _PATH_VARRUN +# define _PATH_VARRUN "/var/run/" +#endif + +#ifdef IPMI_INTF_OPEN +# if defined(HAVE_OPENIPMI_H) +# if defined(HAVE_LINUX_COMPILER_H) +# include <linux/compiler.h> +# endif +# include <linux/ipmi.h> +# elif defined(HAVE_FREEBSD_IPMI_H) +# include <sys/ipmi.h> +# else +# include "plugins/open/open.h" +# endif +# include <sys/poll.h> +#endif /* IPMI_INTF_OPEN */ + +#include <ipmitool/helper.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_sel.h> +#include <ipmitool/ipmi_sdr.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/ipmi_main.h> + +#define WARNING_THRESHOLD 80 +#define DEFAULT_PIDFILE _PATH_VARRUN "ipmievd.pid" +char pidfile[64]; + +/* global variables */ +int verbose = 0; +int csv_output = 0; +uint16_t selwatch_count = 0; /* number of entries in the SEL */ +uint16_t selwatch_lastid = 0; /* current last entry in the SEL */ +int selwatch_pctused = 0; /* current percent usage in the SEL */ +int selwatch_overflow = 0; /* SEL overflow */ +int selwatch_timeout = 10; /* default to 10 seconds */ + +/* event interface definition */ +struct ipmi_event_intf { + char name[16]; + char desc[128]; + char prefix[72]; + int (*setup)(struct ipmi_event_intf * eintf); + int (*wait)(struct ipmi_event_intf * eintf); + int (*read)(struct ipmi_event_intf * eintf); + int (*check)(struct ipmi_event_intf * eintf); + void (*log)(struct ipmi_event_intf * eintf, struct sel_event_record * evt); + struct ipmi_intf * intf; +}; + +/* Data from SEL we are interested in */ +typedef struct sel_data { + uint16_t entries; + int pctused; + int overflow; +} sel_data; + +static void log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt); + +/* ~~~~~~~~~~~~~~~~~~~~~~ openipmi ~~~~~~~~~~~~~~~~~~~~ */ +#ifdef IPMI_INTF_OPEN +static int openipmi_setup(struct ipmi_event_intf * eintf); +static int openipmi_wait(struct ipmi_event_intf * eintf); +static int openipmi_read(struct ipmi_event_intf * eintf); +static struct ipmi_event_intf openipmi_event_intf = { + name: "open", + desc: "OpenIPMI asyncronous notification of events", + prefix: "", + setup: openipmi_setup, + wait: openipmi_wait, + read: openipmi_read, + log: log_event, +}; +#endif +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +/* ~~~~~~~~~~~~~~~~~~~~~~ selwatch ~~~~~~~~~~~~~~~~~~~~ */ +static int selwatch_setup(struct ipmi_event_intf * eintf); +static int selwatch_wait(struct ipmi_event_intf * eintf); +static int selwatch_read(struct ipmi_event_intf * eintf); +static int selwatch_check(struct ipmi_event_intf * eintf); +static struct ipmi_event_intf selwatch_event_intf = { + name: "sel", + desc: "Poll SEL for notification of events", + setup: selwatch_setup, + wait: selwatch_wait, + read: selwatch_read, + check: selwatch_check, + log: log_event, +}; +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +struct ipmi_event_intf * ipmi_event_intf_table[] = { +#ifdef IPMI_INTF_OPEN + &openipmi_event_intf, +#endif + &selwatch_event_intf, + NULL +}; + +/*************************************************************************/ + +static void +ipmievd_usage(void) +{ + lprintf(LOG_NOTICE, "Options:"); + lprintf(LOG_NOTICE, "\ttimeout=# Time between checks for SEL polling method [default=10]"); + lprintf(LOG_NOTICE, "\tdaemon Become a daemon [default]"); + lprintf(LOG_NOTICE, "\tnodaemon Do NOT become a daemon"); +} + +/* ipmi_intf_load - Load an event interface from the table above + * If no interface name is given return first entry + * + * @name: interface name to try and load + * + * returns pointer to inteface structure if found + * returns NULL on error + */ +static struct ipmi_event_intf * +ipmi_event_intf_load(char * name) +{ + struct ipmi_event_intf ** intf; + struct ipmi_event_intf * i; + + if (name == NULL) { + i = ipmi_event_intf_table[0]; + return i; + } + + for (intf = ipmi_event_intf_table; + ((intf != NULL) && (*intf != NULL)); + intf++) { + i = *intf; + if (strncmp(name, i->name, strlen(name)) == 0) { + return i; + } + } + + return NULL; +} + +static int +compute_pctfull(uint16_t entries, uint16_t freespace) +{ + int pctfull = 0; + + if (entries) { + entries *= 16; + freespace += entries; + pctfull = (int)(100 * ( (double)entries / (double)freespace )); + } + return pctfull; +} + + +static void +log_event(struct ipmi_event_intf * eintf, struct sel_event_record * evt) +{ + char *desc; + const char *type; + struct sdr_record_list * sdr; + struct ipmi_intf * intf = eintf->intf; + float trigger_reading = 0.0; + float threshold_reading = 0.0; + + if (evt == NULL) + return; + + if (evt->record_type == 0xf0) { + lprintf(LOG_ALERT, "%sLinux kernel panic: %.11s", + eintf->prefix, (char *) evt + 5); + return; + } + else if (evt->record_type >= 0xc0) { + lprintf(LOG_NOTICE, "%sIPMI Event OEM Record %02x", + eintf->prefix, evt->record_type); + return; + } + + type = ipmi_sel_get_sensor_type_offset(evt->sel_type.standard_type.sensor_type, + evt->sel_type.standard_type.event_data[0]); + + ipmi_get_event_desc(intf, evt, &desc); + + sdr = ipmi_sdr_find_sdr_bynumtype(intf, evt->sel_type.standard_type.gen_id, evt->sel_type.standard_type.sensor_num, + evt->sel_type.standard_type.sensor_type); + + if (sdr == NULL) { + /* could not find matching SDR record */ + if (desc) { + lprintf(LOG_NOTICE, "%s%s sensor - %s", + eintf->prefix, type, desc); + free(desc); + desc = NULL; + } else { + lprintf(LOG_NOTICE, "%s%s sensor %02x", + eintf->prefix, type, + evt->sel_type.standard_type.sensor_num); + } + return; + } + + switch (sdr->type) { + case SDR_RECORD_TYPE_FULL_SENSOR: + if (evt->sel_type.standard_type.event_type == 1) { + /* + * Threshold Event + */ + + /* trigger reading in event data byte 2 */ + if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) { + trigger_reading = sdr_convert_sensor_reading( + sdr->record.full, evt->sel_type.standard_type.event_data[1]); + } + + /* trigger threshold in event data byte 3 */ + if (((evt->sel_type.standard_type.event_data[0] >> 4) & 3) == 1) { + threshold_reading = sdr_convert_sensor_reading( + sdr->record.full, evt->sel_type.standard_type.event_data[2]); + } + + lprintf(LOG_NOTICE, "%s%s sensor %s %s %s (Reading %.*f %s Threshold %.*f %s)", + eintf->prefix, + type, + sdr->record.full->id_string, + desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted"), + (trigger_reading==(int)trigger_reading) ? 0 : 2, + trigger_reading, + ((evt->sel_type.standard_type.event_data[0] & 0xf) % 2) ? ">" : "<", + (threshold_reading==(int)threshold_reading) ? 0 : 2, + threshold_reading, + ipmi_sdr_get_unit_string(sdr->record.common->unit.pct, + sdr->record.common->unit.modifier, + sdr->record.common->unit.type.base, + sdr->record.common->unit.type.modifier)); + } + else if ((evt->sel_type.standard_type.event_type >= 0x2 && evt->sel_type.standard_type.event_type <= 0xc) || + (evt->sel_type.standard_type.event_type == 0x6f)) { + /* + * Discrete Event + */ + lprintf(LOG_NOTICE, "%s%s sensor %s %s %s", + eintf->prefix, type, + sdr->record.full->id_string, desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted")); + if (((evt->sel_type.standard_type.event_data[0] >> 6) & 3) == 1) { + /* previous state and/or severity in event data byte 2 */ + } + } + else if (evt->sel_type.standard_type.event_type >= 0x70 && evt->sel_type.standard_type.event_type <= 0x7f) { + /* + * OEM Event + */ + lprintf(LOG_NOTICE, "%s%s sensor %s %s %s", + eintf->prefix, type, + sdr->record.full->id_string, desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted")); + } + break; + + case SDR_RECORD_TYPE_COMPACT_SENSOR: + lprintf(LOG_NOTICE, "%s%s sensor %s - %s %s", + eintf->prefix, type, + sdr->record.compact->id_string, desc ? : "", + (evt->sel_type.standard_type.event_dir + ? "Deasserted" : "Asserted")); + break; + + default: + lprintf(LOG_NOTICE, "%s%s sensor - %s", + eintf->prefix, type, + evt->sel_type.standard_type.sensor_num, desc ? : ""); + break; + } + + if (desc) { + free(desc); + desc = NULL; + } +} +/*************************************************************************/ + + +/*************************************************************************/ +/** OpenIPMI Functions **/ +/*************************************************************************/ +#ifdef IPMI_INTF_OPEN +static int +openipmi_enable_event_msg_buffer(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t bmc_global_enables; + + /* we must read/modify/write bmc global enables */ + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x2f; /* Get BMC Global Enables */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get BMC Global Enables command failed"); + return -1; + } + else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get BMC Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + bmc_global_enables = rsp->data[0] | 0x04; + req.msg.cmd = 0x2e; /* Set BMC Global Enables */ + req.msg.data = &bmc_global_enables; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Set BMC Global Enables command failed"); + return -1; + } + else if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set BMC Global Enables command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + lprintf(LOG_DEBUG, "BMC Event Message Buffer enabled"); + + return 0; +} + +static int +openipmi_setup(struct ipmi_event_intf * eintf) +{ + int i, r; + + /* enable event message buffer */ + lprintf(LOG_DEBUG, "Enabling event message buffer"); + r = openipmi_enable_event_msg_buffer(eintf->intf); + if (r < 0) { + lprintf(LOG_ERR, "Could not enable event message buffer"); + return -1; + } + + /* enable OpenIPMI event receiver */ + lprintf(LOG_DEBUG, "Enabling event receiver"); + i = 1; + r = ioctl(eintf->intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i); + if (r != 0) { + lperror(LOG_ERR, "Could not enable event receiver"); + return -1; + } + + return 0; +} + +static int +openipmi_read(struct ipmi_event_intf * eintf) +{ + struct ipmi_addr addr; + struct ipmi_recv recv; + uint8_t data[80]; + int rv; + + recv.addr = (unsigned char *) &addr; + recv.addr_len = sizeof(addr); + recv.msg.data = data; + recv.msg.data_len = sizeof(data); + + rv = ioctl(eintf->intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv); + if (rv < 0) { + switch (errno) { + case EINTR: + return 0; /* abort */ + case EMSGSIZE: + recv.msg.data_len = sizeof(data); /* truncated */ + break; + default: + lperror(LOG_ERR, "Unable to receive IPMI message"); + return -1; + } + } + + if (!recv.msg.data || recv.msg.data_len == 0) { + lprintf(LOG_ERR, "No data in event"); + return -1; + } + if (recv.recv_type != IPMI_ASYNC_EVENT_RECV_TYPE) { + lprintf(LOG_ERR, "Type %x is not an event", recv.recv_type); + return -1; + } + + lprintf(LOG_DEBUG, "netfn:%x cmd:%x ccode:%d", + recv.msg.netfn, recv.msg.cmd, recv.msg.data[0]); + + eintf->log(eintf, (struct sel_event_record *)recv.msg.data); + + return 0; +} + +static int +openipmi_wait(struct ipmi_event_intf * eintf) +{ + struct pollfd pfd; + int r; + + for (;;) { + pfd.fd = eintf->intf->fd; /* wait on openipmi device */ + pfd.events = POLLIN; /* wait for input */ + r = poll(&pfd, 1, -1); + + switch (r) { + case 0: + /* timeout is disabled */ + break; + case -1: + lperror(LOG_CRIT, "Unable to read from IPMI device"); + return -1; + default: + if (pfd.revents & POLLIN) + eintf->read(eintf); + } + } + + return 0; +} +#endif /* IPMI_INTF_OPEN */ +/*************************************************************************/ + + +/*************************************************************************/ +/** SEL Watch Functions **/ +/*************************************************************************/ +static int +selwatch_get_data(struct ipmi_intf * intf, struct sel_data *data) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint16_t freespace; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_STORAGE; + req.msg.cmd = IPMI_CMD_GET_SEL_INFO; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get SEL Info command failed"); + return 0; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Get SEL Info command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return 0; + } + + freespace = buf2short(rsp->data + 3); + data->entries = buf2short(rsp->data + 1); + data->pctused = compute_pctfull (data->entries, freespace); + data->overflow = rsp->data[13] & 0x80; + + lprintf(LOG_DEBUG, "SEL count is %d", data->entries); + lprintf(LOG_DEBUG, "SEL freespace is %d", freespace); + lprintf(LOG_DEBUG, "SEL Percent Used: %d%%\n", data->pctused); + lprintf(LOG_DEBUG, "SEL Overflow: %s", data->overflow ? "true" : "false"); + + return 1; +} + +static uint16_t +selwatch_get_lastid(struct ipmi_intf * intf) +{ + int next_id = 0; + uint16_t curr_id = 0; + struct sel_event_record evt; + + if (selwatch_count == 0) + return 0; + + while (next_id != 0xffff) { + curr_id = next_id; + lprintf(LOG_DEBUG, "SEL Next ID: %04x", curr_id); + + next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt); + if (next_id < 0) + break; + if (next_id == 0) { + /* + * usually next_id of zero means end but + * retry because some hardware has quirks + * and will return 0 randomly. + */ + next_id = ipmi_sel_get_std_entry(intf, curr_id, &evt); + if (next_id <= 0) + break; + } + } + + lprintf(LOG_DEBUG, "SEL lastid is %04x", curr_id); + + return curr_id; +} + +static int +selwatch_setup(struct ipmi_event_intf * eintf) +{ + struct sel_data data; + + /* save current sel record count */ + if (selwatch_get_data(eintf->intf, &data)) { + selwatch_count = data.entries; + selwatch_pctused = data.pctused; + selwatch_overflow = data.overflow; + lprintf(LOG_DEBUG, "Current SEL count is %d", selwatch_count); + /* save current last record ID */ + selwatch_lastid = selwatch_get_lastid(eintf->intf); + lprintf(LOG_DEBUG, "Current SEL lastid is %04x", selwatch_lastid); + /* display alert/warning immediatly as startup if relevant */ + if (selwatch_pctused >= WARNING_THRESHOLD) { + lprintf(LOG_WARNING, "SEL buffer used at %d%%, please consider clearing the SEL buffer", selwatch_pctused); + } + if (selwatch_overflow) { + lprintf(LOG_ALERT, "SEL buffer overflow, no SEL message can be logged until the SEL buffer is cleared"); + } + + return 1; + } + + lprintf(LOG_ERR, "Unable to retrieve SEL data"); + return 0; +} + +/* selwatch_check - check for waiting events + * + * this is done by reading sel info and comparing + * the sel count value to what we currently know + */ +static int +selwatch_check(struct ipmi_event_intf * eintf) +{ + uint16_t old_count = selwatch_count; + int old_pctused = selwatch_pctused; + int old_overflow = selwatch_overflow; + struct sel_data data; + + if (selwatch_get_data(eintf->intf, &data)) { + selwatch_count = data.entries; + selwatch_pctused = data.pctused; + selwatch_overflow = data.overflow; + if (old_overflow && !selwatch_overflow) { + lprintf(LOG_NOTICE, "SEL overflow is cleared"); + } else if (!old_overflow && selwatch_overflow) { + lprintf(LOG_ALERT, "SEL buffer overflow, no new SEL message will be logged until the SEL buffer is cleared"); + } + if ((selwatch_pctused >= WARNING_THRESHOLD) && (selwatch_pctused > old_pctused)) { + lprintf(LOG_WARNING, "SEL buffer is %d%% full, please consider clearing the SEL buffer", selwatch_pctused); + } + if (selwatch_count == 0) { + lprintf(LOG_DEBUG, "SEL count is 0 (old=%d), resetting lastid to 0", old_count); + selwatch_lastid = 0; + } else if (selwatch_count < old_count) { + selwatch_lastid = selwatch_get_lastid(eintf->intf); + lprintf(LOG_DEBUG, "SEL count lowered, new SEL lastid is %04x", selwatch_lastid); + } + } + return (selwatch_count > old_count); +} + +static int +selwatch_read(struct ipmi_event_intf * eintf) +{ + uint16_t curr_id = 0; + int next_id = selwatch_lastid; + struct sel_event_record evt; + + if (selwatch_count == 0) + return -1; + + while (next_id != 0xffff) { + curr_id = next_id; + lprintf(LOG_DEBUG, "SEL Read ID: %04x", curr_id); + + next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); + if (next_id < 0) + break; + if (next_id == 0) { + /* + * usually next_id of zero means end but + * retry because some hardware has quirks + * and will return 0 randomly. + */ + next_id = ipmi_sel_get_std_entry(eintf->intf, curr_id, &evt); + if (next_id <= 0) + break; + } + + if (curr_id != selwatch_lastid) + eintf->log(eintf, &evt); + else if (curr_id == 0) + eintf->log(eintf, &evt); + } + + selwatch_lastid = curr_id; + return 0; +} + +static int +selwatch_wait(struct ipmi_event_intf * eintf) +{ + for (;;) { + if (eintf->check(eintf) > 0) { + lprintf(LOG_DEBUG, "New Events"); + eintf->read(eintf); + } + sleep(selwatch_timeout); + } + return 0; +} +/*************************************************************************/ + +static void +ipmievd_cleanup(int signal) +{ + struct stat st1; + + if (lstat(pidfile, &st1) == 0) { + /* cleanup daemon pidfile */ + (void)unlink(pidfile); + } + + exit(EXIT_SUCCESS); +} + +int +ipmievd_main(struct ipmi_event_intf * eintf, int argc, char ** argv) +{ + int i, rc; + int daemon = 1; + struct sigaction act; + + memset(pidfile, 0, 64); + sprintf(pidfile, "%s%d", DEFAULT_PIDFILE, eintf->intf->devnum); + lprintf(LOG_NOTICE, "ipmievd: using pidfile %s", pidfile); + + for (i = 0; i < argc; i++) { + if (strncasecmp(argv[i], "help", 4) == 0) { + ipmievd_usage(); + return 0; + } + if (strncasecmp(argv[i], "daemon", 6) == 0) { + daemon = 1; + } + else if (strncasecmp(argv[i], "nodaemon", 8) == 0) { + daemon = 0; + } + else if (strncasecmp(argv[i], "daemon=", 7) == 0) { + if (strncasecmp(argv[i]+7, "on", 2) == 0 || + strncasecmp(argv[i]+7, "yes", 3) == 0) + daemon = 1; + else if (strncasecmp(argv[i]+7, "off", 3) == 0 || + strncasecmp(argv[i]+7, "no", 2) == 0) + daemon = 0; + } + else if (strncasecmp(argv[i], "timeout=", 8) == 0) { + if ( (str2int(argv[i]+8, &selwatch_timeout) != 0) || + selwatch_timeout < 0) { + lprintf(LOG_ERR, "Invalid input given or out of range for time-out."); + return (-1); + } + } + else if (strncasecmp(argv[i], "pidfile=", 8) == 0) { + memset(pidfile, 0, 64); + strncpy(pidfile, argv[i]+8, + __min(strlen((const char *)(argv[i]+8)), 63)); + } + } + + /* + * We need to open interface before forking daemon + * so error messages are not lost to syslog and + * return code is successfully returned to initscript + */ + if (eintf->intf->open(eintf->intf) < 0) { + lprintf(LOG_ERR, "Unable to open interface"); + return -1; + } + + if (daemon) { + FILE *fp; + struct stat st1; + + if (lstat(pidfile, &st1) == 0) { + /* PID file already exists -> exit. */ + lprintf(LOG_ERR, "PID file '%s' already exists.", pidfile); + lprintf(LOG_ERR, "Perhaps another instance is already running."); + return (-1); + } + + ipmi_start_daemon(eintf->intf); + + umask(022); + fp = ipmi_open_file_write(pidfile); + if (fp == NULL) { + /* Failed to get fp on PID file -> exit. */ + log_halt(); + log_init("ipmievd", daemon, verbose); + lprintf(LOG_ERR, + "Failed to open PID file '%s' for writing. Check file permission.", + pidfile); + exit(EXIT_FAILURE); + } + fprintf(fp, "%d\n", (int)getpid()); + fclose(fp); + } + + /* register signal handler for cleanup */ + act.sa_handler = ipmievd_cleanup; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGTERM, &act, NULL); + + log_halt(); + log_init("ipmievd", daemon, verbose); + + /* generate SDR cache for fast lookups */ + lprintf(LOG_NOTICE, "Reading sensors..."); + ipmi_sdr_list_cache(eintf->intf); + lprintf(LOG_DEBUG, "Sensors cached"); + + /* call event handler setup routine */ + + if (eintf->setup != NULL) { + rc = eintf->setup(eintf); + if (rc < 0) { + lprintf(LOG_ERR, "Error setting up Event Interface %s", eintf->name); + return -1; + } + } + + lprintf(LOG_NOTICE, "Waiting for events..."); + + /* now launch event wait loop */ + if (eintf->wait != NULL) { + rc = eintf->wait(eintf); + if (rc < 0) { + lprintf(LOG_ERR, "Error waiting for events!"); + return -1; + } + } + + return 0; +} + +int +ipmievd_sel_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + struct ipmi_event_intf * eintf; + + eintf = ipmi_event_intf_load("sel"); + if (eintf == NULL) { + lprintf(LOG_ERR, "Unable to load event interface"); + return -1; + } + + eintf->intf = intf; + + if (intf->session != NULL) { + snprintf(eintf->prefix, + strlen((const char *)intf->session->hostname) + 3, + "%s: ", intf->session->hostname); + } + + return ipmievd_main(eintf, argc, argv); +} + +int +ipmievd_open_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + struct ipmi_event_intf * eintf; + + /* only one interface works for this */ + if (strncmp(intf->name, "open", 4) != 0) { + lprintf(LOG_ERR, "Invalid Interface for OpenIPMI Event Handler: %s", intf->name); + return -1; + } + + eintf = ipmi_event_intf_load("open"); + if (eintf == NULL) { + lprintf(LOG_ERR, "Unable to load event interface"); + return -1; + } + + eintf->intf = intf; + + return ipmievd_main(eintf, argc, argv); +} + +struct ipmi_cmd ipmievd_cmd_list[] = { +#ifdef IPMI_INTF_OPEN + { ipmievd_open_main, "open", "Use OpenIPMI for asyncronous notification of events" }, +#endif + { ipmievd_sel_main, "sel", "Poll SEL for notification of events" }, + { NULL } +}; + +int main(int argc, char ** argv) +{ + int rc; + + rc = ipmi_main(argc, argv, ipmievd_cmd_list, NULL); + + if (rc < 0) + exit(EXIT_FAILURE); + else + exit(EXIT_SUCCESS); +} diff --git a/src/ipmishell.c b/src/ipmishell.c new file mode 100644 index 0000000..4eebcd8 --- /dev/null +++ b/src/ipmishell.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2003, 2004 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 <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <ipmitool/helper.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_session.h> +#include <ipmitool/ipmi_main.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#define EXEC_BUF_SIZE 2048 +#define EXEC_ARG_SIZE 64 +#define MAX_PORT 65535 + +extern const struct valstr ipmi_privlvl_vals[]; +extern const struct valstr ipmi_authtype_session_vals[]; + +#ifdef HAVE_READLINE + +/* avoid warnings errors due to non-ANSI type declarations in readline.h */ +#define _FUNCTION_DEF +#define USE_VARARGS +#define PREFER_STDARG + +#include <readline/readline.h> +#include <readline/history.h> +#define RL_PROMPT "ipmitool> " +#define RL_TIMEOUT 30 + +static struct ipmi_intf * shell_intf; + +/* This function attempts to keep lan sessions active + * so they do not time out waiting for user input. The + * readline timeout is set to 1 second but lan session + * timeout is ~60 seconds. + */ +static int rl_event_keepalive(void) +{ + static int internal_timer = 0; + + if (shell_intf == NULL) + return -1; + if (shell_intf->keepalive == NULL) + return 0; +#if defined (RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0402 + if (internal_timer++ < RL_TIMEOUT) +#else + /* In readline < 4.2 keyboard timeout hardcoded to 0.1 second */ + if (internal_timer++ < RL_TIMEOUT * 10) +#endif + return 0; + + internal_timer = 0; + shell_intf->keepalive(shell_intf); + + return 0; +} + +int ipmi_shell_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + char *ptr, *pbuf, **ap, *__argv[EXEC_ARG_SIZE]; + int __argc, rc=0; + + rl_readline_name = "ipmitool"; + + /* this essentially disables command completion + * until its implemented right, otherwise we get + * the current directory contents... */ + rl_bind_key('\t', rl_insert); + + if (intf->keepalive) { + /* hook to keep lan sessions active */ + shell_intf = intf; + rl_event_hook = rl_event_keepalive; +#if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0402 + /* There is a bug in readline 4.2 and later (at least on FreeBSD and NetBSD): + * timeout equal or greater than 1 second causes an infinite loop. */ + rl_set_keyboard_input_timeout(1000 * 1000 - 1); +#endif + } + + while ((pbuf = (char *)readline(RL_PROMPT)) != NULL) { + if (strlen(pbuf) == 0) { + free(pbuf); + pbuf = NULL; + continue; + } + if (strncmp(pbuf, "quit", 4) == 0 || + strncmp(pbuf, "exit", 4) == 0) { + free(pbuf); + pbuf = NULL; + return 0; + } + if (strncmp(pbuf, "help", 4) == 0 || + strncmp(pbuf, "?", 1) == 0) { + ipmi_cmd_print(intf->cmdlist); + free(pbuf); + pbuf = NULL; + continue; + } + + /* for the all-important up arrow :) */ + add_history(pbuf); + + /* change "" and '' with spaces in the middle to ~ */ + ptr = pbuf; + while (*ptr != '\0') { + if (*ptr == '"') { + ptr++; + while (*ptr != '"' && *ptr != '\0') { + if (isspace((int)*ptr)) + *ptr = '~'; + ptr++; + } + } + if (*ptr == '\'') { + ptr++; + while (*ptr != '\'' && *ptr != '\0') { + if (isspace((int)*ptr)) + *ptr = '~'; + ptr++; + } + } + ptr++; + } + + __argc = 0; + ap = __argv; + + for (*ap = strtok(pbuf, " \t"); + *ap != NULL; + *ap = strtok(NULL, " \t")) { + __argc++; + + ptr = *ap; + if (*ptr == '\'') { + memmove(ptr, ptr+1, strlen(ptr)); + while (*ptr != '\'' && *ptr != '\0') { + if (*ptr == '~') + *ptr = ' '; + ptr++; + } + *ptr = '\0'; + } + if (*ptr == '"') { + memmove(ptr, ptr+1, strlen(ptr)); + while (*ptr != '"' && *ptr != '\0') { + if (*ptr == '~') + *ptr = ' '; + ptr++; + } + *ptr = '\0'; + } + + if (**ap != '\0') { + if (++ap >= &__argv[EXEC_ARG_SIZE]) + break; + } + } + + if (__argc && __argv[0]) + rc = ipmi_cmd_run(intf, + __argv[0], + __argc-1, + &(__argv[1])); + + free(pbuf); + pbuf = NULL; + } + printf("\n"); + return rc; +} + +#else /* HAVE_READLINE */ + +int +ipmi_shell_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + lprintf(LOG_ERR, "Compiled without readline, shell is disabled"); + return -1; +} + +#endif /* HAVE_READLINE */ + +int ipmi_echo_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + int i; + + for (i=0; i<argc; i++) { + printf("%s ", argv[i]); + } + printf("\n"); + + return 0; +} + +static void +ipmi_set_usage(void) +{ + lprintf(LOG_NOTICE, "Usage: set <option> <value>\n"); + lprintf(LOG_NOTICE, "Options are:"); + lprintf(LOG_NOTICE, " hostname <host> Session hostname"); + lprintf(LOG_NOTICE, " username <user> Session username"); + lprintf(LOG_NOTICE, " password <pass> Session password"); + lprintf(LOG_NOTICE, " privlvl <level> Session privilege level force"); + lprintf(LOG_NOTICE, " authtype <type> Authentication type force"); + lprintf(LOG_NOTICE, " localaddr <addr> Local IPMB address"); + lprintf(LOG_NOTICE, " targetaddr <addr> Remote target IPMB address"); + lprintf(LOG_NOTICE, " port <port> Remote RMCP port"); + lprintf(LOG_NOTICE, " csv [level] enable output in comma separated format"); + lprintf(LOG_NOTICE, " verbose [level] Verbose level"); + lprintf(LOG_NOTICE, ""); +} + +int ipmi_set_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + if (argc == 0 || strncmp(argv[0], "help", 4) == 0) { + ipmi_set_usage(); + return -1; + } + + /* these options can have no arguments */ + if (strncmp(argv[0], "verbose", 7) == 0) { + if (argc > 1) { + if (str2int(argv[1], &verbose) != 0) { + lprintf(LOG_ERR, + "Given verbose '%s' argument is invalid.", + argv[1]); + return (-1); + } + } else { + verbose = verbose + 1; + } + return 0; + } + if (strncmp(argv[0], "csv", 3) == 0) { + if (argc > 1) { + if (str2int(argv[1], &csv_output) != 0) { + lprintf(LOG_ERR, + "Given csv '%s' argument is invalid.", + argv[1]); + return (-1); + } + } else { + csv_output = 1; + } + return 0; + } + + /* the rest need an argument */ + if (argc == 1) { + ipmi_set_usage(); + return -1; + } + + if (strncmp(argv[0], "host", 4) == 0 || + strncmp(argv[0], "hostname", 8) == 0) { + ipmi_intf_session_set_hostname(intf, argv[1]); + if (intf->session == NULL) { + lprintf(LOG_ERR, "Failed to set session hostname."); + return (-1); + } + printf("Set session hostname to %s\n", + intf->session->hostname); + } + else if (strncmp(argv[0], "user", 4) == 0 || + strncmp(argv[0], "username", 8) == 0) { + ipmi_intf_session_set_username(intf, argv[1]); + if (intf->session == NULL) { + lprintf(LOG_ERR, "Failed to set session username."); + return (-1); + } + printf("Set session username to %s\n", + intf->session->username); + } + else if (strncmp(argv[0], "pass", 4) == 0 || + strncmp(argv[0], "password", 8) == 0) { + ipmi_intf_session_set_password(intf, argv[1]); + if (intf->session == NULL) { + lprintf(LOG_ERR, "Failed to set session password."); + return (-1); + } + printf("Set session password\n"); + } + else if (strncmp(argv[0], "authtype", 8) == 0) { + int authtype; + authtype = str2val(argv[1], ipmi_authtype_session_vals); + if (authtype == 0xFF) { + lprintf(LOG_ERR, "Invalid authtype: %s", + argv[1]); + return (-1); + } + ipmi_intf_session_set_authtype(intf, authtype); + if (intf->session == NULL) { + lprintf(LOG_ERR, "Failed to set session authtype."); + return (-1); + } + printf("Set session authtype to %s\n", + val2str(intf->session->authtype_set, + ipmi_authtype_session_vals)); + } + else if (strncmp(argv[0], "privlvl", 7) == 0) { + int privlvl; + privlvl = str2val(argv[1], ipmi_privlvl_vals); + if (privlvl == 0xFF) { + lprintf(LOG_ERR, "Invalid privilege level: %s", + argv[1]); + return (-1); + } + ipmi_intf_session_set_privlvl(intf, privlvl); + if (intf->session == NULL) { + lprintf(LOG_ERR, + "Failed to set session privilege level."); + return (-1); + } + printf("Set session privilege level to %s\n", + val2str(intf->session->privlvl, + ipmi_privlvl_vals)); + } + else if (strncmp(argv[0], "port", 4) == 0) { + int port = 0; + if (str2int(argv[1], &port) != 0 || port > MAX_PORT) { + lprintf(LOG_ERR, "Given port '%s' is invalid.", + argv[1]); + return (-1); + } + ipmi_intf_session_set_port(intf, port); + if (intf->session == NULL) { + lprintf(LOG_ERR, "Failed to set session port."); + return (-1); + } + printf("Set session port to %d\n", intf->session->port); + } + else if (strncmp(argv[0], "localaddr", 9) == 0) { + uint8_t my_addr = 0; + if (str2uchar(argv[1], &my_addr) != 0) { + lprintf(LOG_ERR, "Given localaddr '%s' is invalid.", + argv[1]); + return (-1); + } + intf->my_addr = my_addr; + printf("Set local IPMB address to 0x%02x\n", intf->my_addr); + } + else if (strncmp(argv[0], "targetaddr", 10) == 0) { + uint8_t target_addr = 0; + if (str2uchar(argv[1], &target_addr) != 0) { + lprintf(LOG_ERR, "Given targetaddr '%s' is invalid.", + argv[1]); + return (-1); + } + intf->target_addr = target_addr; + printf("Set remote IPMB address to 0x%02x\n", intf->target_addr); + } + else { + ipmi_set_usage(); + return -1; + } + return 0; +} + +int ipmi_exec_main(struct ipmi_intf * intf, int argc, char ** argv) +{ + FILE * fp; + char buf[EXEC_BUF_SIZE]; + char * ptr, * tok, * ret, * tmp; + int __argc, i, r; + char * __argv[EXEC_ARG_SIZE]; + int rc=0; + + if (argc < 1) { + lprintf(LOG_ERR, "Usage: exec <filename>"); + return -1; + } + + fp = ipmi_open_file_read(argv[0]); + if (fp == NULL) + return -1; + + while (feof(fp) == 0) { + ret = fgets(buf, EXEC_BUF_SIZE, fp); + if (ret == NULL) + continue; + + /* clip off optional comment tail indicated by # */ + ptr = strchr(buf, '#'); + if (ptr) + *ptr = '\0'; + else + ptr = buf + strlen(buf); + + /* change "" and '' with spaces in the middle to ~ */ + ptr = buf; + while (*ptr != '\0') { + if (*ptr == '"') { + ptr++; + while (*ptr != '"' && *ptr != '\0') { + if (isspace((int)*ptr)) + *ptr = '~'; + ptr++; + } + } + if (*ptr == '\'') { + ptr++; + while (*ptr != '\'' && *ptr != '\0') { + if (isspace((int)*ptr)) + *ptr = '~'; + ptr++; + } + } + ptr++; + } + + /* clip off trailing and leading whitespace */ + ptr--; + while (isspace((int)*ptr) && ptr >= buf) + *ptr-- = '\0'; + ptr = buf; + while (isspace((int)*ptr)) + ptr++; + if (strlen(ptr) == 0) + continue; + + /* parse it and make argument list */ + __argc = 0; + for (tok = strtok(ptr, " "); tok != NULL; tok = strtok(NULL, " ")) { + if (__argc < EXEC_ARG_SIZE) { + __argv[__argc++] = strdup(tok); + if (__argv[__argc-1] == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + tmp = __argv[__argc-1]; + if (*tmp == '\'') { + memmove(tmp, tmp+1, strlen(tmp)); + while (*tmp != '\'' && *tmp != '\0') { + if (*tmp == '~') + *tmp = ' '; + tmp++; + } + *tmp = '\0'; + } + if (*tmp == '"') { + memmove(tmp, tmp+1, strlen(tmp)); + while (*tmp != '"' && *tmp != '\0') { + if (*tmp == '~') + *tmp = ' '; + tmp++; + } + *tmp = '\0'; + } + } + } + + /* now run the command, save the result if not successful */ + r = ipmi_cmd_run(intf, __argv[0], __argc-1, &(__argv[1])); + if (r != 0) + rc = r; + + /* free argument list */ + for (i=0; i<__argc; i++) { + if (__argv[i] != NULL) { + free(__argv[i]); + __argv[i] = NULL; + } + } + } + + fclose(fp); + return rc; +} diff --git a/src/ipmitool.c b/src/ipmitool.c new file mode 100644 index 0000000..6230e5c --- /dev/null +++ b/src/ipmitool.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. + * Use is subject to license terms. + */ + +/* + * 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 <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_main.h> + +#include <ipmitool/ipmi_sdr.h> +#include <ipmitool/ipmi_gendev.h> +#include <ipmitool/ipmi_sel.h> +#include <ipmitool/ipmi_fru.h> +#include <ipmitool/ipmi_sol.h> +#include <ipmitool/ipmi_isol.h> +#include <ipmitool/ipmi_tsol.h> +#include <ipmitool/ipmi_lanp.h> +#include <ipmitool/ipmi_chassis.h> +#include <ipmitool/ipmi_mc.h> +#include <ipmitool/ipmi_sensor.h> +#include <ipmitool/ipmi_channel.h> +#include <ipmitool/ipmi_session.h> +#include <ipmitool/ipmi_event.h> +#include <ipmitool/ipmi_user.h> +#include <ipmitool/ipmi_raw.h> +#include <ipmitool/ipmi_pef.h> +#include <ipmitool/ipmi_oem.h> +#include <ipmitool/ipmi_sunoem.h> +#include <ipmitool/ipmi_fwum.h> +#include <ipmitool/ipmi_picmg.h> +#include <ipmitool/ipmi_kontronoem.h> +#include <ipmitool/ipmi_firewall.h> +#include <ipmitool/ipmi_hpmfwupg.h> +#include <ipmitool/ipmi_delloem.h> +#include <ipmitool/ipmi_ekanalyzer.h> +#include <ipmitool/ipmi_ime.h> +#include <ipmitool/ipmi_dcmi.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_READLINE +extern int ipmi_shell_main(struct ipmi_intf * intf, int argc, char ** argv); +#endif +extern int ipmi_echo_main(struct ipmi_intf * intf, int argc, char ** argv); +extern int ipmi_set_main(struct ipmi_intf * intf, int argc, char ** argv); +extern int ipmi_exec_main(struct ipmi_intf * intf, int argc, char ** argv); + + +int csv_output = 0; +int verbose = 0; + +struct ipmi_cmd ipmitool_cmd_list[] = { + { ipmi_raw_main, "raw", "Send a RAW IPMI request and print response" }, + { ipmi_rawi2c_main, "i2c", "Send an I2C Master Write-Read command and print response" }, + { ipmi_rawspd_main, "spd", "Print SPD info from remote I2C device" }, + { ipmi_lanp_main, "lan", "Configure LAN Channels" }, + { ipmi_chassis_main, "chassis", "Get chassis status and set power state" }, + { ipmi_power_main, "power", "Shortcut to chassis power commands" }, + { ipmi_event_main, "event", "Send pre-defined events to MC" }, + { ipmi_mc_main, "mc", "Management Controller status and global enables" }, + { ipmi_mc_main, "bmc", NULL }, /* for backwards compatibility */ + { ipmi_sdr_main, "sdr", "Print Sensor Data Repository entries and readings" }, + { ipmi_sensor_main, "sensor", "Print detailed sensor information" }, + { ipmi_fru_main, "fru", "Print built-in FRU and scan SDR for FRU locators" }, + { ipmi_gendev_main, "gendev", "Read/Write Device associated with Generic Device locators sdr" }, + { ipmi_sel_main, "sel", "Print System Event Log (SEL)" }, + { ipmi_pef_main, "pef", "Configure Platform Event Filtering (PEF)" }, + { ipmi_sol_main, "sol", "Configure and connect IPMIv2.0 Serial-over-LAN" }, + { ipmi_tsol_main, "tsol", "Configure and connect with Tyan IPMIv1.5 Serial-over-LAN" }, + { ipmi_isol_main, "isol", "Configure IPMIv1.5 Serial-over-LAN" }, + { ipmi_user_main, "user", "Configure Management Controller users" }, + { ipmi_channel_main, "channel", "Configure Management Controller channels" }, + { ipmi_session_main, "session", "Print session information" }, + { ipmi_dcmi_main, "dcmi", "Data Center Management Interface"}, + { ipmi_sunoem_main, "sunoem", "OEM Commands for Sun servers" }, + { ipmi_kontronoem_main, "kontronoem", "OEM Commands for Kontron devices"}, + { ipmi_picmg_main, "picmg", "Run a PICMG/ATCA extended cmd"}, + { ipmi_fwum_main, "fwum", "Update IPMC using Kontron OEM Firmware Update Manager" }, + { ipmi_firewall_main,"firewall","Configure Firmware Firewall" }, + { ipmi_delloem_main, "delloem", "OEM Commands for Dell systems" }, +#ifdef HAVE_READLINE + { ipmi_shell_main, "shell", "Launch interactive IPMI shell" }, +#endif + { ipmi_exec_main, "exec", "Run list of commands from file" }, + { ipmi_set_main, "set", "Set runtime variable for shell and exec" }, + { ipmi_echo_main, "echo", NULL }, /* for echoing lines to stdout in scripts */ + { ipmi_hpmfwupg_main,"hpm", "Update HPM components using PICMG HPM.1 file"}, + { ipmi_ekanalyzer_main,"ekanalyzer", "run FRU-Ekeying analyzer using FRU files"}, + { ipmi_ime_main, "ime", "Update Intel Manageability Engine Firmware"}, + { NULL }, +}; + +int +main(int argc, char ** argv) +{ + int rc; + + rc = ipmi_main(argc, argv, ipmitool_cmd_list, NULL); + + if (rc < 0) + exit(EXIT_FAILURE); + else + exit(EXIT_SUCCESS); +} diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am new file mode 100644 index 0000000..19b5f11 --- /dev/null +++ b/src/plugins/Makefile.am @@ -0,0 +1,43 @@ +# 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ +DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy + +noinst_LTLIBRARIES = libintf.la +libintf_la_SOURCES = ipmi_intf.c +libintf_la_LDFLAGS = -export-dynamic +libintf_la_LIBADD = @IPMITOOL_INTF_LIB@ +libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@ + diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in new file mode 100644 index 0000000..7cd39ca --- /dev/null +++ b/src/plugins/Makefile.in @@ -0,0 +1,695 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am_libintf_la_OBJECTS = ipmi_intf.lo +libintf_la_OBJECTS = $(am_libintf_la_OBJECTS) +libintf_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libintf_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_la_SOURCES) +DIST_SOURCES = $(libintf_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ +DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy +noinst_LTLIBRARIES = libintf.la +libintf_la_SOURCES = ipmi_intf.c +libintf_la_LDFLAGS = -export-dynamic +libintf_la_LIBADD = @IPMITOOL_INTF_LIB@ +libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@ +all: all-recursive + +.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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf.la: $(libintf_la_OBJECTS) $(libintf_la_DEPENDENCIES) $(EXTRA_libintf_la_DEPENDENCIES) + $(libintf_la_LINK) $(libintf_la_OBJECTS) $(libintf_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipmi_intf.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + clean-noinstLTLIBRARIES ctags ctags-recursive distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# 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/src/plugins/bmc/Makefile.am b/src/plugins/bmc/Makefile.am new file mode 100644 index 0000000..66080d6 --- /dev/null +++ b/src/plugins/bmc/Makefile.am @@ -0,0 +1,41 @@ +# Copyright (c) 2004 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_bmc.la +noinst_LTLIBRARIES = @INTF_BMC_LIB@ +libintf_bmc_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_bmc_la_SOURCES = \ + bmc.c bmc.h \ + bmc_intf.h + diff --git a/src/plugins/bmc/Makefile.in b/src/plugins/bmc/Makefile.in new file mode 100644 index 0000000..0b67a01 --- /dev/null +++ b/src/plugins/bmc/Makefile.in @@ -0,0 +1,541 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# Copyright (c) 2004 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/bmc +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_bmc_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_bmc_la_OBJECTS = bmc.lo +libintf_bmc_la_OBJECTS = $(am_libintf_bmc_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_bmc_la_SOURCES) +DIST_SOURCES = $(libintf_bmc_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_bmc.la +noinst_LTLIBRARIES = @INTF_BMC_LIB@ +libintf_bmc_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_bmc_la_SOURCES = \ + bmc.c bmc.h \ + bmc_intf.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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/bmc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/bmc/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_bmc.la: $(libintf_bmc_la_OBJECTS) $(libintf_bmc_la_DEPENDENCIES) $(EXTRA_libintf_bmc_la_DEPENDENCIES) + $(LINK) $(libintf_bmc_la_OBJECTS) $(libintf_bmc_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bmc.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/bmc/bmc.c b/src/plugins/bmc/bmc.c new file mode 100644 index 0000000..b88b077 --- /dev/null +++ b/src/plugins/bmc/bmc.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2004 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. + */ + + +/* + * interface routines between ipmitool and the bmc kernel driver + */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stropts.h> +#include <stddef.h> +#include <stropts.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include "bmc_intf.h" + +#include "bmc.h" + +static int curr_seq; +static int bmc_method(int fd, int *if_type); +struct ipmi_rs *(*sendrecv_fn)(struct ipmi_intf *, struct ipmi_rq *) = NULL; +extern int verbose; + +static void dump_request(bmc_req_t *request); +static void dump_response(bmc_rsp_t *response); +static struct ipmi_rs *ipmi_bmc_send_cmd_ioctl(struct ipmi_intf *intf, + struct ipmi_rq *req); +static struct ipmi_rs *ipmi_bmc_send_cmd_putmsg(struct ipmi_intf *intf, + struct ipmi_rq *req); + +#define MESSAGE_BUFSIZE 1024 + +struct ipmi_intf ipmi_bmc_intf = { + name: "bmc", + desc: "IPMI v2.0 BMC interface", + open: ipmi_bmc_open, + close: ipmi_bmc_close, + sendrecv: ipmi_bmc_send_cmd}; + +void +ipmi_bmc_close(struct ipmi_intf *intf) +{ + if (intf && intf->fd >= 0) + close(intf->fd); + + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; + intf->fd = -1; +} + +int +ipmi_bmc_open(struct ipmi_intf *intf) +{ + int method; + + if (!intf) + return -1; + + /* Open local device */ + intf->fd = open(BMC_DEV, O_RDWR); + + if (intf->fd <= 0) { + perror("Could not open bmc device"); + return (-1); + } + curr_seq = 0; + + intf->opened = 1; + + if (bmc_method(intf->fd, &method) < 0) { + perror("Could not determine bmc messaging interface"); + return (-1); + } + + sendrecv_fn = (method == BMC_PUTMSG_METHOD) ? + ipmi_bmc_send_cmd_putmsg : ipmi_bmc_send_cmd_ioctl; + + intf->manufacturer_id = ipmi_get_oem(intf); + return (intf->fd); +} + +struct ipmi_rs * +ipmi_bmc_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req) +{ + /* If not already opened open the device or network connection */ + if (!intf->opened && intf->open && intf->open(intf) < 0) + return NULL; + + /* sendrecv_fn cannot be NULL at this point */ + return ((*sendrecv_fn)(intf, req)); +} + +static struct ipmi_rs * +ipmi_bmc_send_cmd_ioctl(struct ipmi_intf *intf, struct ipmi_rq *req) +{ + struct strioctl istr; + static struct bmc_reqrsp reqrsp; + static struct ipmi_rs rsp; + + memset(&reqrsp, 0, sizeof (reqrsp)); + reqrsp.req.fn = req->msg.netfn; + reqrsp.req.lun = 0; + reqrsp.req.cmd = req->msg.cmd; + reqrsp.req.datalength = req->msg.data_len; + memcpy(reqrsp.req.data, req->msg.data, req->msg.data_len); + reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE; + + istr.ic_cmd = IOCTL_IPMI_KCS_ACTION; + istr.ic_timout = 0; + istr.ic_dp = (char *)&reqrsp; + istr.ic_len = sizeof (struct bmc_reqrsp); + + if (verbose) { + printf("--\n"); + dump_request(&reqrsp.req); + printf("--\n"); + } + + if (ioctl(intf->fd, I_STR, &istr) < 0) { + perror("BMC IOCTL: I_STR"); + return (NULL); + } + + if (verbose > 2) { + dump_response(&reqrsp.rsp); + printf("--\n"); + } + + memset(&rsp, 0, sizeof (struct ipmi_rs)); + rsp.ccode = reqrsp.rsp.ccode; + rsp.data_len = reqrsp.rsp.datalength; + + /* Decrement for sizeof lun, cmd and ccode */ + rsp.data_len -= 3; + + if (!rsp.ccode && (rsp.data_len > 0)) + memcpy(rsp.data, reqrsp.rsp.data, rsp.data_len); + + return (&rsp); +} + +static struct ipmi_rs * +ipmi_bmc_send_cmd_putmsg(struct ipmi_intf *intf, struct ipmi_rq *req) +{ + struct strbuf sb; + int flags = 0; + static uint32_t msg_seq = 0; + + /* + * The length of the message structure is equal to the size of the + * bmc_req_t structure, PLUS any additional data space in excess of + * the data space already reserved in the data member + <n> for + * the rest of the members in the bmc_msg_t structure. + */ + int msgsz = offsetof(bmc_msg_t, msg) + sizeof(bmc_req_t) + + ((req->msg.data_len > SEND_MAX_PAYLOAD_SIZE) ? + (req->msg.data_len - SEND_MAX_PAYLOAD_SIZE) : 0); + bmc_msg_t *msg = malloc(msgsz); + bmc_req_t *request = (bmc_req_t *)&msg->msg[0]; + bmc_rsp_t *response; + static struct ipmi_rs rsp; + struct ipmi_rs *ret = NULL; + + msg->m_type = BMC_MSG_REQUEST; + msg->m_id = msg_seq++; + request->fn = req->msg.netfn; + request->lun = 0; + request->cmd = req->msg.cmd; + request->datalength = req->msg.data_len; + memcpy(request->data, req->msg.data, req->msg.data_len); + + sb.len = msgsz; + sb.buf = (unsigned char *)msg; + + if (verbose) { + printf("--\n"); + dump_request(request); + printf("--\n"); + } + + if (putmsg(intf->fd, NULL, &sb, 0) < 0) { + perror("BMC putmsg: "); + free(msg); + msg = NULL; + return (NULL); + } + + free(msg); + msg = NULL; + + sb.buf = malloc(MESSAGE_BUFSIZE); + sb.maxlen = MESSAGE_BUFSIZE; + + if (getmsg(intf->fd, NULL, &sb, &flags) < 0) { + perror("BMC getmsg: "); + free(sb.buf); + sb.buf = NULL; + return (NULL); + } + + msg = (bmc_msg_t *)sb.buf; + + if (verbose > 3) { + printf("Got msg (id 0x%x) type 0x%x\n", msg->m_id, msg->m_type); + } + + + /* Did we get an error back from the stream? */ + switch (msg->m_type) { + + case BMC_MSG_RESPONSE: + response = (bmc_rsp_t *)&msg->msg[0]; + + if (verbose > 2) { + dump_response(response); + printf("--\n"); + } + + memset(&rsp, 0, sizeof (struct ipmi_rs)); + rsp.ccode = response->ccode; + rsp.data_len = response->datalength; + + if (!rsp.ccode && (rsp.data_len > 0)) + memcpy(rsp.data, response->data, rsp.data_len); + + ret = &rsp; + break; + + case BMC_MSG_ERROR: + /* In case of an error, msg->msg[0] has the error code */ + printf("bmc_send_cmd: %s\n", strerror(msg->msg[0])); + break; + + } + + free(sb.buf); + sb.buf = NULL; + return (ret); +} + +/* + * Determine which interface to use. Returns the interface method + * to use. + */ +static int +bmc_method(int fd, int *if_type) +{ + struct strioctl istr; + int retval = 0; + uint8_t method = BMC_PUTMSG_METHOD; + + istr.ic_cmd = IOCTL_IPMI_INTERFACE_METHOD; + istr.ic_timout = 0; + istr.ic_dp = (uint8_t *)&method; + istr.ic_len = 1; + + /* + * If the ioctl doesn't exist, we should get an EINVAL back. + * Bail out on any other error. + */ + if (ioctl(fd, I_STR, &istr) < 0) { + + if (errno != EINVAL) + retval = -1; + else + method = BMC_IOCTL_METHOD; + } + + if (retval == 0) + *if_type = method; + + return (retval); +} + +static void +dump_request(bmc_req_t *request) +{ + int i; + + printf("BMC req.fn : 0x%x\n", request->fn); + printf("BMC req.lun : 0x%x\n", request->lun); + printf("BMC req.cmd : 0x%x\n", request->cmd); + printf("BMC req.datalength : 0x%x\n", request->datalength); + printf("BMC req.data : "); + + if (request->datalength > 0) { + for (i = 0; i < request->datalength; i++) + printf("0x%x ", request->data[i]); + } else { + printf("<NONE>"); + } + printf("\n"); +} + +static void +dump_response(bmc_rsp_t *response) +{ + int i; + + printf("BMC rsp.fn : 0x%x\n", response->fn); + printf("BMC rsp.lun : 0x%x\n", response->lun); + printf("BMC rsp.cmd : 0x%x\n", response->cmd); + printf("BMC rsp.ccode : 0x%x\n", response->ccode); + printf("BMC rsp.datalength : 0x%x\n", response->datalength); + printf("BMC rsp.data : "); + + if (response->datalength > 0) { + for (i = 0; i < response->datalength; i++) + printf("0x%x ", response->data[i]); + } else { + printf("<NONE>"); + } + printf("\n"); +} diff --git a/src/plugins/bmc/bmc.h b/src/plugins/bmc/bmc.h new file mode 100644 index 0000000..0138710 --- /dev/null +++ b/src/plugins/bmc/bmc.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2004 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_BMC_H_ +#define _IPMI_BMC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <ipmitool/ipmi.h> + +#define BMC_DEV "/dev/bmc" + +struct ipmi_rs *ipmi_bmc_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req); +int ipmi_bmc_open(struct ipmi_intf *intf); +void ipmi_bmc_close(struct ipmi_intf *intf); + +#ifdef __cplusplus +} +#endif + +#endif /* _IPMI_BMC_H_ */ diff --git a/src/plugins/bmc/bmc_intf.h b/src/plugins/bmc/bmc_intf.h new file mode 100644 index 0000000..c73e4c1 --- /dev/null +++ b/src/plugins/bmc/bmc_intf.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2004 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 _BMC_INTF_H +#define _BMC_INTF_H + +#pragma ident "@(#)bmc_intf.h 1.2 05/03/07 SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BMC_SUCCESS 0x0 +#define BMC_FAILURE 0x1 + +#define BMC_NETFN_CHASSIS 0x0 +#define BMC_NETFN_BRIDGE 0x2 +#define BMC_NETFN_SE 0x4 +#define BMC_NETFN_APP 0x6 +#define BMC_NETFN_FIRMWARE 0x8 +#define BMC_NETFN_STORAGE 0xa +#define BMC_NETFN_TRANSPORT 0xc + +#define SEND_MAX_PAYLOAD_SIZE 34 /* MAX payload */ +#define RECV_MAX_PAYLOAD_SIZE 33 /* MAX payload */ +#define BMC_MIN_RESPONSE_SIZE 3 +#define BMC_MIN_REQUEST_SIZE 2 +#define BMC_MAX_RESPONSE_SIZE (BMC_MIN_RESPONSE_SIZE + RECV_MAX_PAYLOAD_SIZE) +#define BMC_MAX_REQUEST_SIZE (BMC_MIN_REQUEST_SIZE + BMC_MAX_RESPONSE_SIZE) + +#define BUF_SIZE 256 +#define MAX_BUF_SIZE 256 + +/* + * Useful macros + */ +#define FORM_NETFNLUN(net, lun) ((((net) << 2) | ((lun) & 0x3))) +#define GET_NETFN(netfn) (((netfn) >> 2) & 0x3f) +#define GET_LUN(netfn) (netfn & 0x3) +#define RESP_NETFN(nflun) ((nflun) | 1) +#define ISREQUEST(nl) (((nl) & 1) == 0) /* test for request */ +#define ISRESPONSE(nl) (((nl) & 1) == 1) /* test for response */ + + +/* for checking BMC specific stuff */ +#define BMC_GET_DEVICE_ID 0x1 /* GET DEVICE ID COMMAND */ +#define BMC_IPMI_15_VER 0x51 /* IPMI 1.5 definion */ + +/* BMC Completion Code and OEM Completion Code */ +#define BMC_IPMI_UNSPECIFIC_ERROR 0xFF /* Unspecific Error */ +#define BMC_IPMI_INVALID_COMMAND 0xC1 /* Invalid Command */ +#define BMC_IPMI_COMMAND_TIMEOUT 0xC3 /* Command Timeout */ +#define BMC_IPMI_DATA_LENGTH_EXCEED 0xC8 /* DataLength exceeded limit */ +#define BMC_IPMI_OEM_FAILURE_SENDBMC 0x7E /* Cannot send BMC req */ + + +#define IOCTL_IPMI_KCS_ACTION 0x01 +#define IOCTL_IPMI_INTERFACE_METHOD 0x02 + +/* Interface methods returned from IOCTL_IPMI_INTERFACE_METHOD ioctl: */ + +#define BMC_IOCTL_METHOD 0 /* Not returned from ioctl, */ + /* but can be used by */ + /* applications that want to */ + /* compare against an */ + /* alternative method. */ +#define BMC_PUTMSG_METHOD 1 + +/* + * bmc_req_t is the data structure to send + * request packet from applications to the driver + * module. + * + * the request pkt is mainly for KCS-interface-BMC + * messages. Since the system interface is session-less + * connections, the packet won't have any session + * information. + * + * the data payload will be 2 bytes less than max + * BMC supported packet size. + * the address of the responder is always BMC and so + * rsSa field is not required. + */ +typedef struct bmc_req { + uint8_t fn; /* netFn for command */ + uint8_t lun; /* logical unit on responder */ + uint8_t cmd; /* command */ + uint8_t datalength; /* length of following data */ + uint8_t data[SEND_MAX_PAYLOAD_SIZE]; /* request data */ +} bmc_req_t; + +/* + * bmc_rsp_t is the data structure to send + * respond packet from applications to the driver + * module. + * + * the respond pkt is mainly for KCS-interface-BMC + * messages. Since the system interface is session-less + * connections, the packet won't have any session + * information. + * + * the data payload will be 2 bytes less than max + * BMC supported packet size. + */ +typedef struct bmc_rsp { + uint8_t fn; /* netFn for command */ + uint8_t lun; /* logical unit on responder */ + uint8_t cmd; /* command */ + uint8_t ccode; /* completion code */ + uint8_t datalength; /* Length */ + uint8_t data[RECV_MAX_PAYLOAD_SIZE]; /* response */ +} bmc_rsp_t; + +/* + * the data structure for synchronous operation via ioctl (DEPRECATED) + */ +typedef struct bmc_reqrsp { + bmc_req_t req; /* request half */ + bmc_rsp_t rsp; /* response half */ +} bmc_reqrsp_t; + + +/* + * The new way of communicating with the bmc driver is to use putmsg() to + * send a message of a particular type. Replies from the driver also have this + * form, and will require the user to process the type field before examining + * the rest of the reply. + * + * The only change that must be observed when using the request and response + * structures defined above is as follows: + * when sending messages to the bmc driver, the data portion is now variable + * (the caller must allocate enough space to store the all structure members, + * plus enough space to cover the amount of data in the request), e.g.: + * + * bmc_msg_t *msg = malloc(offsetof(bmc_msg_t, msg) + sizeof(bmc_req_t) + 10); + * + * The amount allocated for the message is (# of bytes before the msg field) + + * the size of a bmc_req_t (which includes SEND_MAX_PAYLOAD_SIZE + * bytes in the data field), plus an additional 10 bytes for the data + * field (so the data field would occupy (SEND_MAX_PAYLOAD_SIZE + 10) + * bytes). The datalength member must reflect the amount of data in the + * request's data field (as was required when using the ioctl interface). + */ +typedef struct bmc_msg { + uint8_t m_type; /* Message type (see below) */ + uint32_t m_id; /* Message ID */ + uint8_t reserved[32]; + uint8_t msg[1]; /* Variable length message data */ +} bmc_msg_t; + + +/* + * An error response passed back from the bmc driver will have its m_id + * field set to BMC_UNKNOWN_MSG_ID if a message is sent to it that is not + * at least as large as a bmc_msg_t. + */ +#define BMC_UNKNOWN_MSG_ID ~((uint32_t)0) + + +/* + * Possible values for the m_type field in bmc_msg_t: + */ +#define BMC_MSG_REQUEST 1 /* BMC request (as above, sent to the */ + /* driver by the user), bmc_msg.msg */ + /* begins with the bmc_req_t */ + /* structure. */ +#define BMC_MSG_RESPONSE 2 /* BMC response (sent by the driver) */ + /* bmc_msg.msg begins with the */ + /* bmc_rsp_t structure. */ +#define BMC_MSG_ERROR 3 /* Error while processing a user msg */ + /* msg[0] is the error code */ + /* (interpret as an errno value) */ + +#ifdef __cplusplus +} +#endif + +#endif /* _BMC_INTF_H */ diff --git a/src/plugins/dummy/Makefile.am b/src/plugins/dummy/Makefile.am new file mode 100644 index 0000000..8a53bbe --- /dev/null +++ b/src/plugins/dummy/Makefile.am @@ -0,0 +1,8 @@ +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_dummy.la +noinst_LTLIBRARIES = @INTF_DUMMY_LIB@ +libintf_dummy_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_dummy_la_SOURCES = dummy.c diff --git a/src/plugins/dummy/Makefile.in b/src/plugins/dummy/Makefile.in new file mode 100644 index 0000000..944b2da --- /dev/null +++ b/src/plugins/dummy/Makefile.in @@ -0,0 +1,508 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/dummy +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_dummy_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_dummy_la_OBJECTS = dummy.lo +libintf_dummy_la_OBJECTS = $(am_libintf_dummy_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_dummy_la_SOURCES) +DIST_SOURCES = $(libintf_dummy_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_dummy.la +noinst_LTLIBRARIES = @INTF_DUMMY_LIB@ +libintf_dummy_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_dummy_la_SOURCES = dummy.c +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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/dummy/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/dummy/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_dummy.la: $(libintf_dummy_la_OBJECTS) $(libintf_dummy_la_DEPENDENCIES) $(EXTRA_libintf_dummy_la_DEPENDENCIES) + $(LINK) $(libintf_dummy_la_OBJECTS) $(libintf_dummy_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/dummy/dummy.c b/src/plugins/dummy/dummy.c new file mode 100644 index 0000000..eb2d086 --- /dev/null +++ b/src/plugins/dummy/dummy.c @@ -0,0 +1,286 @@ +/* Copyright (c) 2013 Zdenek Styblik, 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 Zdenek Styblik 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. + * Zdenek Styblik 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 + * Zdenek Styblik 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 Zdenek Styblik HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <unistd.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/helper.h> +#include <ipmitool/log.h> + +#include "dummy.h" + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +extern int verbose; + +/* data_read - read data from socket + * + * @data_ptr - pointer to memory where to store read data + * @data_len - how much to read from socket + * + * return 0 on success, otherwise (-1) + */ +int +data_read(int fd, void *data_ptr, int data_len) +{ + int rc = 0; + int data_read = 0; + int data_total = 0; + int try = 1; + int errno_save = 0; + if (data_len < 0) { + return (-1); + } + while (data_total < data_len && try < 4) { + errno = 0; + /* TODO - add poll() */ + data_read = read(fd, data_ptr, data_len); + errno_save = errno; + if (data_read > 0) { + data_total+= data_read; + } + if (errno_save != 0) { + if (errno_save == EINTR || errno_save == EAGAIN) { + try++; + sleep(2); + continue; + } else { + errno = errno_save; + perror("dummy failed on read(): "); + rc = (-1); + break; + } + } + } + if (try > 3 && data_total != data_len) { + rc = (-1); + } + return rc; +} + +/* data_write - write data to the socket + * + * @data_ptr - ptr to data to send + * @data_len - how long is the data to send + * + * returns 0 on success, otherwise (-1) + */ +int +data_write(int fd, void *data_ptr, int data_len) +{ + int rc = 0; + int data_written = 0; + int data_total = 0; + int try = 1; + int errno_save = 0; + if (data_len < 0) { + return (-1); + } + while (data_total < data_len && try < 4) { + errno = 0; + /* TODO - add poll() */ + data_written = write(fd, data_ptr, data_len); + errno_save = errno; + if (data_read > 0) { + data_total+= data_written; + } + if (errno_save != 0) { + if (errno_save == EINTR || errno_save == EAGAIN) { + try++; + sleep(2); + continue; + } else { + errno = errno_save; + perror("dummy failed on read(): "); + rc = (-1); + break; + } + } + } + if (try > 3 && data_total != data_len) { + rc = (-1); + } + return rc; +} + +/* ipmi_dummyipmi_close - send "BYE" and close socket + * + * @intf - ptr to initialize ipmi_intf struct + * + * returns void + */ +static void +ipmi_dummyipmi_close(struct ipmi_intf *intf) +{ + struct dummy_rq req; + int data_total = 0; + int data_written = 0; + int try = 0; + if (intf->fd < 0) { + return; + } + memset(&req, 0, sizeof(req)); + req.msg.netfn = 0x3f; + req.msg.cmd = 0xff; + if (data_write(intf->fd, &req, sizeof(req)) != 0) { + lprintf(LOG_ERR, "dummy failed to send 'BYE'"); + } + close(intf->fd); + intf->fd = (-1); + intf->opened = 0; +} + +/* ipmi_dummyipmi_open - open socket and prepare ipmi_intf struct + * + * @intf - ptr to ipmi_inf struct + * + * returns 0 on success, (-1) on error + */ +static int +ipmi_dummyipmi_open(struct ipmi_intf *intf) +{ + struct sockaddr_un address; + int len; + int rc; + + if (intf->opened == 1) { + return intf->fd; + } + intf->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (intf->fd == (-1)) { + lprintf(LOG_ERR, "dummy failed on socket()"); + return (-1); + } + address.sun_family = AF_UNIX; + strcpy(address.sun_path, DUMMY_SOCKET_PATH); + len = sizeof(address); + rc = connect(intf->fd, (struct sockaddr *)&address, len); + if (rc != 0) { + perror("dummy failed on connect(): "); + return (-1); + } + intf->opened = 1; + return intf->fd; +} + +/* ipmi_dummyipmi_send_cmd - send IPMI payload and await reply + * + * @intf - ptr to initialized ipmi_intf struct + * @req - ptr to ipmi_rq struct to send + * + * return pointer to struct ipmi_rs OR NULL on error + */ +static struct ipmi_rs* +ipmi_dummyipmi_send_cmd(struct ipmi_intf *intf, struct ipmi_rq *req) +{ + static struct ipmi_rs rsp; + struct dummy_rq req_dummy; + struct dummy_rs rsp_dummy; + if (intf == NULL || intf->fd < 0 || intf->opened != 1) { + lprintf(LOG_ERR, "dummy failed on intf check."); + return NULL; + } + + memset(&req_dummy, 0, sizeof(req_dummy)); + req_dummy.msg.netfn = req->msg.netfn; + req_dummy.msg.lun = req->msg.lun; + req_dummy.msg.cmd = req->msg.cmd; + req_dummy.msg.target_cmd = req->msg.target_cmd; + req_dummy.msg.data_len = req->msg.data_len; + req_dummy.msg.data = req->msg.data; + if (verbose) { + lprintf(LOG_NOTICE, ">>> IPMI req"); + lprintf(LOG_NOTICE, "msg.data_len: %i", + req_dummy.msg.data_len); + lprintf(LOG_NOTICE, "msg.netfn: %x", req_dummy.msg.netfn); + lprintf(LOG_NOTICE, "msg.cmd: %x", req_dummy.msg.cmd); + lprintf(LOG_NOTICE, "msg.target_cmd: %x", + req_dummy.msg.target_cmd); + lprintf(LOG_NOTICE, "msg.lun: %x", req_dummy.msg.lun); + lprintf(LOG_NOTICE, ">>>"); + } + if (data_write(intf->fd, &req_dummy, + sizeof(struct dummy_rq)) != 0) { + return NULL; + } + if (req->msg.data_len > 0) { + if (data_write(intf->fd, (uint8_t *)(req->msg.data), + req_dummy.msg.data_len) != 0) { + return NULL; + } + } + + memset(&rsp_dummy, 0, sizeof(rsp_dummy)); + if (data_read(intf->fd, &rsp_dummy, sizeof(struct dummy_rs)) != 0) { + return NULL; + } + if (rsp_dummy.data_len > 0) { + if (data_read(intf->fd, (uint8_t *)&rsp.data, + rsp_dummy.data_len) != 0) { + return NULL; + } + } + rsp.ccode = rsp_dummy.ccode; + rsp.data_len = rsp_dummy.data_len; + rsp.msg.netfn = rsp_dummy.msg.netfn; + rsp.msg.cmd = rsp_dummy.msg.cmd; + rsp.msg.seq = rsp_dummy.msg.seq; + rsp.msg.lun = rsp_dummy.msg.lun; + if (verbose) { + lprintf(LOG_NOTICE, "<<< IPMI rsp"); + lprintf(LOG_NOTICE, "ccode: %x", rsp.ccode); + lprintf(LOG_NOTICE, "data_len: %i", rsp.data_len); + lprintf(LOG_NOTICE, "msg.netfn: %x", rsp.msg.netfn); + lprintf(LOG_NOTICE, "msg.cmd: %x", rsp.msg.cmd); + lprintf(LOG_NOTICE, "msg.seq: %x", rsp.msg.seq); + lprintf(LOG_NOTICE, "msg.lun: %x", rsp.msg.lun); + lprintf(LOG_NOTICE, "<<<"); + } + return &rsp; +} + +struct ipmi_intf ipmi_dummy_intf = { + name: "dummy", + desc: "Linux DummyIPMI Interface", + open: ipmi_dummyipmi_open, + close: ipmi_dummyipmi_close, + sendrecv: ipmi_dummyipmi_send_cmd, + my_addr: IPMI_BMC_SLAVE_ADDR, + target_addr: IPMI_BMC_SLAVE_ADDR, +}; diff --git a/src/plugins/free/Makefile.am b/src/plugins/free/Makefile.am new file mode 100644 index 0000000..028281f --- /dev/null +++ b/src/plugins/free/Makefile.am @@ -0,0 +1,9 @@ +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_free.la +noinst_LTLIBRARIES = @INTF_FREE_LIB@ +libintf_free_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_free_la_SOURCES = free.c +libintf_free_la_LDFLAGS = -lfreeipmi diff --git a/src/plugins/free/Makefile.in b/src/plugins/free/Makefile.in new file mode 100644 index 0000000..22d1938 --- /dev/null +++ b/src/plugins/free/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/free +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_free_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_free_la_OBJECTS = free.lo +libintf_free_la_OBJECTS = $(am_libintf_free_la_OBJECTS) +libintf_free_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libintf_free_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_free_la_SOURCES) +DIST_SOURCES = $(libintf_free_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_free.la +noinst_LTLIBRARIES = @INTF_FREE_LIB@ +libintf_free_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_free_la_SOURCES = free.c +libintf_free_la_LDFLAGS = -lfreeipmi +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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/free/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/free/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_free.la: $(libintf_free_la_OBJECTS) $(libintf_free_la_DEPENDENCIES) $(EXTRA_libintf_free_la_DEPENDENCIES) + $(libintf_free_la_LINK) $(libintf_free_la_OBJECTS) $(libintf_free_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/free.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/free/free.c b/src/plugins/free/free.c new file mode 100644 index 0000000..f89925d --- /dev/null +++ b/src/plugins/free/free.c @@ -0,0 +1,318 @@ +/* + * 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> + +#include <freeipmi/freeipmi.h> +#if IPMI_INTF_FREE_0_3_0 || IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0 +#include <freeipmi/udm/ipmi-udm.h> +#endif + +#if IPMI_INTF_FREE_0_6_0 +ipmi_ctx_t dev = NULL; +#else /* !IPMI_INTF_FREE_0_6_0 */ +ipmi_device_t dev = NULL; +#endif /* !IPMI_INTF_FREE_0_6_0 */ + +extern int verbose; + +static int ipmi_free_open(struct ipmi_intf * intf) +{ + int kcs_ret = -1, ssif_ret = -1; + + if (getuid() != 0) { + fprintf(stderr, "Permission denied, must be root\n"); + return -1; + } + +#if IPMI_INTF_FREE_0_3_0 + if (!(dev = ipmi_open_inband (IPMI_DEVICE_KCS, + 0, + 0, + 0, + NULL, + IPMI_FLAGS_DEFAULT))) { + if (!(dev = ipmi_open_inband (IPMI_DEVICE_SSIF, + 0, + 0, + 0, + NULL, + IPMI_FLAGS_DEFAULT))) { + perror("ipmi_open_inband()"); + goto cleanup; + } + } +#elif IPMI_INTF_FREE_0_4_0 + if (!(dev = ipmi_device_create())) { + perror("ipmi_device_create"); + goto cleanup; + } + if (ipmi_open_inband (dev, + IPMI_DEVICE_KCS, + 0, + 0, + 0, + NULL, + IPMI_FLAGS_DEFAULT) < 0) { + if (ipmi_open_inband (dev, + IPMI_DEVICE_SSIF, + 0, + 0, + 0, + NULL, + IPMI_FLAGS_DEFAULT) < 0) { + fprintf(stderr, + "ipmi_open_inband(): %s\n", + ipmi_device_strerror(ipmi_device_errnum(dev))); + goto cleanup; + } + } +#elif IPMI_INTF_FREE_0_5_0 + if (!(dev = ipmi_device_create())) { + perror("ipmi_device_create"); + goto cleanup; + } + if (ipmi_open_inband (dev, + IPMI_DEVICE_KCS, + 0, + 0, + 0, + NULL, + 0, + IPMI_FLAGS_DEFAULT) < 0) { + if (ipmi_open_inband (dev, + IPMI_DEVICE_SSIF, + 0, + 0, + 0, + NULL, + 0, + IPMI_FLAGS_DEFAULT) < 0) { + fprintf(stderr, + "ipmi_open_inband(): %s\n", + ipmi_device_strerror(ipmi_device_errnum(dev))); + goto cleanup; + } + } +#elif IPMI_INTF_FREE_0_6_0 + if (!(dev = ipmi_ctx_create())) { + perror("ipmi_ctx_create"); + goto cleanup; + } + if (ipmi_ctx_open_inband (dev, + IPMI_DEVICE_KCS, + 0, + 0, + 0, + NULL, + 0, + IPMI_FLAGS_DEFAULT) < 0) { + if (ipmi_ctx_open_inband (dev, + IPMI_DEVICE_SSIF, + 0, + 0, + 0, + NULL, + 0, + IPMI_FLAGS_DEFAULT) < 0) { + fprintf(stderr, + "ipmi_open_inband(): %s\n", + ipmi_ctx_strerror(ipmi_ctx_errnum(dev))); + goto cleanup; + } + } +#endif + + intf->opened = 1; + intf->manufacturer_id = ipmi_get_oem(intf); + return 0; + cleanup: + if (dev) { +#if IPMI_INTF_FREE_0_3_0 + ipmi_close_device(dev); +#elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0 + ipmi_close_device(dev); + ipmi_device_destroy(dev); +#elif IPMI_INTF_FREE_0_6_0 + ipmi_ctx_close(dev); + ipmi_ctx_destroy(dev); +#endif + } + return -1; +} + +static void ipmi_free_close(struct ipmi_intf * intf) +{ + if (dev) { +#if IPMI_INTF_FREE_0_3_0 + ipmi_close_device(dev); +#elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0 + ipmi_close_device(dev); + ipmi_device_destroy(dev); +#elif IPMI_INTF_FREE_0_6_0 + ipmi_ctx_close(dev); + ipmi_ctx_destroy(dev); +#endif + } + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; +} + +static struct ipmi_rs * ipmi_free_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + u_int8_t lun = req->msg.lun; + u_int8_t cmd = req->msg.cmd; + u_int8_t netfn = req->msg.netfn; + u_int8_t rq_buf[IPMI_BUF_SIZE]; + u_int8_t rs_buf[IPMI_BUF_SIZE]; + u_int32_t rs_buf_len = IPMI_BUF_SIZE; + int32_t rs_len; + + static struct ipmi_rs rsp; + + /* achu: FreeIPMI requests have the cmd as the first byte of + * the data. Responses have cmd as the first byte and + * completion code as the second byte. This differs from some + * other APIs, so it must be compensated for within the ipmitool + * interface. + */ + + if (!intf || !req) + return NULL; + + if (!intf->opened && intf->open && intf->open(intf) < 0) + return NULL; + + if (req->msg.data_len > IPMI_BUF_SIZE) + return NULL; + + memset(rq_buf, '\0', IPMI_BUF_SIZE); + memset(rs_buf, '\0', IPMI_BUF_SIZE); + memcpy(rq_buf, &cmd, 1); + + if (req->msg.data) + memcpy(rq_buf + 1, req->msg.data, req->msg.data_len); + + if (intf->target_addr != 0 + && intf->target_addr != IPMI_BMC_SLAVE_ADDR) { +#if IPMI_INTF_FREE_BRIDGING + if ((rs_len = ipmi_cmd_raw_ipmb(dev, + intf->target_channel, + intf->target_addr, + lun, + netfn, + rq_buf, + req->msg.data_len + 1, + rs_buf, + rs_buf_len)) < 0) { + if (verbose > 3) + fprintf(stderr, + "ipmi_cmd_raw_ipmb: %s\n", + ipmi_ctx_strerror(ipmi_ctx_errnum(dev))); + /* Compared to FreeIPMI, user is expected to input + * the target channel on the command line, it is not automatically + * discovered. So that is the likely cause of an error. + * + * Instead of returning an error, return a bad response so output + * of ipmitool commands looks like other interfaces + */ + rs_len = 2; + rs_buf[0] = 0; + rs_buf[1] = 0xC1; /* invalid command */ + } +#else /* !IPMI_INTF_FREE_BRIDGING */ + if (verbose > 3) + fprintf(stderr, "sensor bridging not supported in this driver version"); + /* instead of returning an error, return a bad response so output + * of ipmitool commands looks like other interfaces + */ + rs_len = 2; + rs_buf[0] = 0; + rs_buf[1] = 0xC1; /* invalid command */ +#endif /* !IPMI_INTF_FREE_BRIDGING */ + } + else { + if ((rs_len = ipmi_cmd_raw(dev, + lun, + netfn, + rq_buf, + req->msg.data_len + 1, + rs_buf, + rs_buf_len)) < 0) { +#if IPMI_INTF_FREE_0_3_0 + perror("ipmi_cmd_raw"); +#elif IPMI_INTF_FREE_0_4_0 || IPMI_INTF_FREE_0_5_0 + fprintf(stderr, + "ipmi_cmd_raw: %s\n", + ipmi_device_strerror(ipmi_device_errnum(dev))); +#elif IPMI_INTF_FREE_0_6_0 + fprintf(stderr, + "ipmi_cmd_raw: %s\n", + ipmi_ctx_strerror(ipmi_ctx_errnum(dev))); +#endif + return NULL; + } + } + + memset(&rsp, 0, sizeof(struct ipmi_rs)); + rsp.ccode = (unsigned char)rs_buf[1]; + rsp.data_len = (int)rs_len - 2; + + if (!rsp.ccode && rsp.data_len) + memcpy(rsp.data, rs_buf + 2, rsp.data_len); + + return &rsp; +} + +struct ipmi_intf ipmi_free_intf = { + name: "free", + desc: "FreeIPMI IPMI Interface", + open: ipmi_free_open, + close: ipmi_free_close, + sendrecv: ipmi_free_send_cmd, + target_addr: IPMI_BMC_SLAVE_ADDR, +}; + diff --git a/src/plugins/imb/Makefile.am b/src/plugins/imb/Makefile.am new file mode 100644 index 0000000..91d5966 --- /dev/null +++ b/src/plugins/imb/Makefile.am @@ -0,0 +1,39 @@ +# 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_imb.la +noinst_LTLIBRARIES = @INTF_IMB_LIB@ +libintf_imb_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_imb_la_SOURCES = imbapi.c imbapi.h imb.c + diff --git a/src/plugins/imb/Makefile.in b/src/plugins/imb/Makefile.in new file mode 100644 index 0000000..27cefb1 --- /dev/null +++ b/src/plugins/imb/Makefile.in @@ -0,0 +1,539 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/imb +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_imb_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_imb_la_OBJECTS = imbapi.lo imb.lo +libintf_imb_la_OBJECTS = $(am_libintf_imb_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_imb_la_SOURCES) +DIST_SOURCES = $(libintf_imb_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_imb.la +noinst_LTLIBRARIES = @INTF_IMB_LIB@ +libintf_imb_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_imb_la_SOURCES = imbapi.c imbapi.h imb.c +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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/imb/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/imb/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_imb.la: $(libintf_imb_la_OBJECTS) $(libintf_imb_la_DEPENDENCIES) $(EXTRA_libintf_imb_la_DEPENDENCIES) + $(LINK) $(libintf_imb_la_OBJECTS) $(libintf_imb_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imbapi.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/imb/imb.c b/src/plugins/imb/imb.c new file mode 100644 index 0000000..cb97e81 --- /dev/null +++ b/src/plugins/imb/imb.c @@ -0,0 +1,131 @@ +/* + * 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 <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/helper.h> + +#include "imbapi.h" + +#define IPMI_IMB_TIMEOUT (1000 * 1000) +#define IPMI_IMB_MAX_RETRY 3 +#define IPMI_IMB_DEV "/dev/imb" +#define IPMI_IMB_BUF_SIZE 64 + +extern int verbose; + +static int ipmi_imb_open(struct ipmi_intf * intf) +{ + struct stat stbuf; + + if (stat(IPMI_IMB_DEV, &stbuf) < 0) { + printf("Error: no IMB driver found at %s!\n", IPMI_IMB_DEV); + return -1; + } + + intf->opened = 1; + intf->manufacturer_id = ipmi_get_oem(intf); + + return 0; +} + +static void ipmi_imb_close(struct ipmi_intf * intf) +{ + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; +} + +static struct ipmi_rs * ipmi_imb_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + IMBPREQUESTDATA imbreq; + static struct ipmi_rs rsp; + int status, i; + unsigned char ccode; + + imbreq.rsSa = IPMI_BMC_SLAVE_ADDR; + imbreq.rsLun = 0; + imbreq.busType = 0; + imbreq.netFn = req->msg.netfn; + imbreq.cmdType = req->msg.cmd; + + imbreq.data = req->msg.data; + imbreq.dataLength = req->msg.data_len; + + if (verbose > 1) { + printf("IMB rsSa : %x\n", imbreq.rsSa); + printf("IMB netFn : %x\n", imbreq.netFn); + printf("IMB cmdType : %x\n", imbreq.cmdType); + printf("IMB dataLength : %d\n", imbreq.dataLength); + } + + rsp.data_len = IPMI_IMB_BUF_SIZE; + memset(rsp.data, 0, rsp.data_len); + + for (i=0; i<IPMI_IMB_MAX_RETRY; i++) { + if (verbose > 2) + printbuf(imbreq.data, imbreq.dataLength, "ipmi_imb request"); + status = SendTimedImbpRequest(&imbreq, IPMI_IMB_TIMEOUT, + rsp.data, &rsp.data_len, &ccode); + if (status == 0) { + if (verbose > 2) + printbuf(rsp.data, rsp.data_len, "ipmi_imb response"); + break; + } + /* error */ + printf("Error sending IMB request, status=%x ccode=%x\n", + status, ccode); + } + + rsp.ccode = ccode; + + return &rsp; +} + +struct ipmi_intf ipmi_imb_intf = { + name: "imb", + desc: "Intel IMB Interface", + open: ipmi_imb_open, + close: ipmi_imb_close, + sendrecv: ipmi_imb_send_cmd, + target_addr: IPMI_BMC_SLAVE_ADDR, +}; + diff --git a/src/plugins/imb/imbapi.c b/src/plugins/imb/imbapi.c new file mode 100644 index 0000000..37d3abe --- /dev/null +++ b/src/plugins/imb/imbapi.c @@ -0,0 +1,2090 @@ +/*M* +// PVCS: +// $Workfile: imbapi.c $ +// $Revision: 1.5 $ +// $Modtime: 06 Aug 2001 13:16:56 $ +// $Author: stybla $ +// +// 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 +// +// +*M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002, 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. + *----------------------------------------------------------------------*/ +/* + * $Log: imbapi.c,v $ + * Revision 1.5 2013/07/22 08:35:23 stybla + * ID: 65 - Fixes for configure.in for cross compilation + * + * 'src/plugins/imb/imbapi.c' - don't cast NULL to int, ever!!! + * + * Revision 1.4 2013/07/21 11:33:57 stybla + * ID: 65 - Fixes for configure.in for cross compilation + * + * NULL should never be cast to an int. + * + * Commit for Dan Gora + * + * Revision 1.3 2013/01/18 12:46:52 ledva + * 3600962 descriptor leaks + * + * Revision 1.2 2004/08/31 23:52:58 iceblink + * fix lots of little errors that show up with -Werror -Wall + * + * Revision 1.1 2004/08/27 16:33:25 iceblink + * add support for Intel IMB kernel driver (for legacy kernel support) + * imbapi.[ch] code is BSD licensed and taken from panicsel.sf.net + * + * + * Rev 1.12ac 04 Apr 2002 13:17:58 arcress + * Mods for open-source & various compile cleanup mods + * + * Rev 1.12 06 Aug 2001 13:17:58 spoola + * Fixed tracker items #15667, #15666, #15664 + * + * Rev 1.0 05 Sep 1999 17:20:30 mramacha + * Linux checkin + * + * Note: This file is derived from the NTWORK version of the imbapi.c + * It was decided to create OS specific ones for Linux and Solaris. + * It has all the fixes that went into the imbapi.c up to Rev 1.12 + * in the 2.2 NTWORK branch. + */ + +#define IMB_API + +#ifdef WIN32 +#define NO_MACRO_ARGS 1 +#include <windows.h> +#include <stdio.h> + +#else /* LINUX, SCO_UW, UNIX */ +#include <unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#endif +#include "imbapi.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.*/ +#ifndef NO_MACRO_ARGS +#ifdef LINUX_DEBUG +#define DEBUG(format, args...) printf(format, ##args) +#else +#define DEBUG(format, args...) +#endif +#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 */ + + +/*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 exsisting policy of using +// pre-processor directives to separate os-specific code (pai 11/21) */ + +HANDLE AsyncEventHandle = 0; +//static void * AsyncEventObject = 0; +static int IpmiVersion; + +/*//////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +///////////////////////////////////////////////////////////////////////////// */ + +IO_STATUS_BLOCK NTstatus; /*dummy place holder. See deviceiocontrol. */ +static HANDLE hDevice1; +static HANDLE hDevice; +/*mutex_t deviceMutex; */ +static int fDriverTyp; /*from ipmicmd.c*/ + +/*//////////////////////////////////////////////////////////////////// +// 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 +int open_imb(void) +{ +/* 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[16]; + DWORD respLength; + BYTE completionCode; + + if (hDevice1 == 0) /*INVALID_HANDLE_VALUE*/ + { + // + // Open IMB driver device + // + hDevice = CreateFile( "\\\\.\\Imb", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hDevice == NULL || hDevice == INVALID_HANDLE_VALUE) + return (0); /*FALSE*/ + + // 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 = 16; + if ( (SendTimedImbpRequest ( &requestData, (DWORD)400, + respBuffer, &respLength, &completionCode + ) != ACCESN_OK ) || ( completionCode != 0) ) + { + CloseHandle(hDevice); + return (0); /*FALSE*/ + } + hDevice1 = hDevice; + + if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)) + IpmiVersion = IPMI_09_VERSION; + else { + if ( respBuffer[4] == 0x51 ) + IpmiVersion = IPMI_15_VERSION; + else + IpmiVersion = IPMI_10_VERSION; + } + } + return (1); /*TRUE*/ + +} /*end open_imb for Win32 */ + +#else /* LINUX, SCO_UW, etc. */ + +int open_imb(void) +{ +/* 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[16]; + DWORD respLength; + BYTE completionCode; + + int my_ret_code; + + if (hDevice1 == 0) + { +#ifndef NO_MACRO_ARGS + DEBUG("%s: opening the driver\n", __FUNCTION__); +#endif + /* + printf("open_imb: " + "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) + { + char buf[128]; + + hDevice1 = 0; + if (fDriverTyp != 0) { /*not 1st time*/ + sprintf(buf,"%s %s: open(%s) failed", + __FILE__,__FUNCTION__,IMB_DEVICE); + perror(buf); + } + return (0); + } + + /* 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 = 16; +#ifndef NO_MACRO_ARGS + DEBUG("%s: opened driver, getting IPMI version\n", __FUNCTION__); +#endif + if ( ((my_ret_code = SendTimedImbpRequest(&requestData, (DWORD)400, + respBuffer, (int *)&respLength, &completionCode) + ) != ACCESN_OK ) || ( completionCode != 0) ) + { + printf("%s: SendTimedImbpRequest error. Ret = %d CC = 0x%X\n", + __FUNCTION__, my_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] == 0x51 ) + IpmiVersion = IPMI_15_VERSION; + else + IpmiVersion = IPMI_10_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 + +/*---------------------------------------------------------------------* + * ipmi_open_ia & ipmi_close_ia + *---------------------------------------------------------------------*/ +int ipmi_open_ia(void) +{ + int rc = 0; + rc = open_imb(); /*sets hDevice1*/ + if (rc == 1) rc = 0; + else rc = -1; + return(rc); +} + +int ipmi_close_ia(void) +{ + int rc = 0; + if (hDevice1 != 0) { +#ifdef WIN32 + CloseHandle(hDevice1); +#else + rc = close(hDevice1); +#endif + } + return(rc); +} + +#ifndef WIN32 +/*/////////////////////////////////////////////////////////////////////////// +// 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( + HANDLE dummey_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; + int ioctl_status; + + rc = open_imb(); + if (rc == 0) { + return FALSE; + } + + /* + //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 + if (cbInBuffer > 41) cbInBuffer = 41; /* Intel driver max buf */ + + 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.*/ + + if ( (ioctl_status = ioctl(hDevice1, dwIoControlCode,&s) ) <0) { +#ifndef NO_MACRO_ARGS + DEBUG("%s %s: ioctl cmd = 0x%x failed", + __FILE__,__FUNCTION__,dwIoControlCode); +#endif + /* mutex_unlock(&deviceMutex); */ + return FALSE; + } + /* 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 + +/*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_IMB_SEND_MESSAGE, + 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 = i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_SEND_MESSAGE, + 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 = 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_IMB_SEND_MESSAGE, + 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) */ +/*/////////////////////////////////////////////////////////////////////////// +// 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 = i; + + req->flags = 0; + req->timeOut = timeOut * 1000; /* convert to uSec units */ + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_SEND_MESSAGE, + 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) */ +/*/////////////////////////////////////////////////////////////////////////// +// 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 = 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_IMB_SEND_MESSAGE, + 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; +} + +/*/////////////////////////////////////////////////////////////////////////// +// 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 dest controller */ + ) +{ + BYTE responseData[MAX_BUFFER_SIZE]; + ImbResponseBuffer * resp = (ImbResponseBuffer *) responseData; + DWORD respLength = sizeof( responseData ); + BYTE requestData[MAX_BUFFER_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 = reqPtr->dataLength; + +#ifndef NO_MACRO_ARGS + DEBUG("cmd=%02x, pdata=%p, datalen=%x\n", req->req.cmd, + reqPtr->data, reqPtr->dataLength ); +#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 + + + status = DeviceIoControl( hDevice, + IOCTL_IMB_SEND_MESSAGE, + requestData, + sizeof( requestData ), + & 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 ); +#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; +} + + +/*///////////////////////////////////////////////////////////////////////// +//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 = 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_IMB_SEND_MESSAGE, + 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; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + 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; + } + + if ( (lun == RESERVED_LUN) || + (lun != ((((ImbPacket *)(resp->data))->nfLn) & 0x3 )) + ) + { + *seqNo = resp->thisSeq; + continue; + } + + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + + } + else + { + /* it is a 1.0 or above version */ + + if (resp->data[0] != (BYTE)channelNumber) + { + *seqNo = resp->thisSeq; + continue; + } + + memcpy( msgPtr, &(resp->data[1]), respLength-1 ); + *msgLen = respLength-1; + + + } + + /* + // 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; + ImbAsyncResponse * resp = (ImbAsyncResponse *) responseData; + DWORD respLength = sizeof( responseData ); + ImbAsyncRequest req; + + while(1) + { + + + if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) ) + return ACCESN_ERROR; + + 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; + } + + if ( (lun == RESERVED_LUN) || + (lun != ((((ImbPacket *)(resp->data))->nfLn) & 0x3 )) + ) + { + *seqNo = resp->thisSeq; + continue; + } + + + memcpy( msgPtr, resp->data, respLength ); + *msgLen = respLength; + + } + 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; + + if ((resp->data[0] & 0x0f) != (BYTE)channelNumber) + { + *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; + + + } + + /* + // 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 (unsigned int eventId ) +{ + int dummy; + int respLength = 0; + BOOL status; + + /* confirm that app is not using a bad Id */ + + + if ( AsyncEventHandle != (HANDLE) eventId) + return ACCESN_ERROR; + + status = DeviceIoControl(hDevice, + IOCTL_IMB_CHECK_EVENT, + &AsyncEventHandle, + sizeof(HANDLE ), + &dummy, + 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; +} + + +/*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 (unsigned int *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, + (DWORD)sizeof(HANDLE ), + (LPDWORD) & respLength, + NULL + ); +#ifndef NO_MACRO_ARGS + DEBUG("%s: DeviceIoControl status = %d\n",__FUNCTION__, status); +#endif + + if( (respLength != sizeof(int)) || (status != TRUE )) + return ACCESN_ERROR; + + /* printf("imbapi: Register handle = %x\n",AsyncEventHandle); *//*++++*/ + *handleId = (unsigned int) 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 (unsigned int handleId, int iFlag) + +{ + BOOL status; + DWORD respLength ; + int dummy; + + iFlag = iFlag; /* to keep compiler happy We are not using this flag*/ + + if ( AsyncEventHandle != (HANDLE) handleId) + return ACCESN_ERROR; + + status = DeviceIoControl(hDevice, + IOCTL_IMB_DEREGISTER_ASYNC_OBJ, + &AsyncEventHandle, + (DWORD)sizeof(HANDLE ), + &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; +} + +/*///////////////////////////////////////////////////////////////////////// +// 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 == 0 || 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; + unsigned int length = addressLength; + off_t startpAddress = (off_t)startAddress; + unsigned int diff; + caddr_t startvAddress; + + if ((startAddress == 0) || (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__,IMB_DEVICE); + 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 = (long)(startvAddress + diff); + close(fd); + 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(&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*/ + + +/*///////////////////////////////////////////////////////////////////////////// +// 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 IpmiVersion; +} + diff --git a/src/plugins/imb/imbapi.h b/src/plugins/imb/imbapi.h new file mode 100644 index 0000000..74975c6 --- /dev/null +++ b/src/plugins/imb/imbapi.h @@ -0,0 +1,652 @@ +/*M* +// PVCS: +// $Workfile: imb_api.h $ +// $Revision: 1.2 $ +// $Modtime: Jul 22 2002 16:40:32 $ +// $Author: iceblink $ +// +// Combined include files needed for imbapi.c +// + *M*/ +/*----------------------------------------------------------------------* +The BSD License +Copyright (c) 2002, 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. + *----------------------------------------------------------------------*/ +#ifndef _WINDEFS_H +#define _WINDEFS_H +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef NULL +#define NULL 0 +#endif +#ifndef WIN32 +/* WIN32 defines this in stdio.h */ +#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 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; +typedef DWORD NTSTATUS; +/* + 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 unsigned char * PUCHAR; +typedef unsigned short * PUSHORT; +typedef unsigned long * PULONG; +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; + +#ifndef _SYS_TYPES_H +#ifndef _CADDR_T +#define _CADDR_T + typedef char * caddr_t; +#endif +#endif +/* + 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 /* */ + +#ifndef WIN32 +#define FIELD_OFFSET(type, field) ((LONG)&(((type *)0)->field)) +#define UNREFERENCED_PARAMETER(x) +typedef int HANDLE; +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#endif +typedef HANDLE *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 + */ +#ifndef WIN32 +#define CTL_CODE(DeviceType, Function, Method, Access)\ + _IO(DeviceType & 0x00FF, Function & 0x00FF) +#else +#define CTL_CODE( DeviceType, Function, Method, Access ) ((ULONG)( \ + ((ULONG)(DeviceType) << 16) | ((ULONG)(Access) << 14) | ((ULONG)(Function) << 2) | ((ULONG)Method) \ +)) +#endif +#endif /*_WINDEFS_H */ +/*----------------------------------------------------------------------*/ +#ifndef _SMI_H +#define _SMI_H +#define SMI_Version1_00 0x00001000 +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*/ +}; +#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 +#define STATUS_PENDING (0x00000103U) +// see <win2000ddk>\inc\winnt.h(1171) +#endif +#define STATUS_INVALID_PARAMETER (0xC000000DU) +#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 33 +/* + * 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[1]; +} ImbRequest; +typedef struct { + DWORD flags; /* request flags*/ +#define NO_RESPONSE_EXPECTED 0x01 /*dont wait around for an IMB response*/ + DWORD timeOut; /* in uSec units*/ + ImbRequest req; /* message buffer*/ +} ImbRequestBuffer; +#define MIN_IMB_REQ_BUF_SIZE 13 /* a buffer without any request data*/ +/************************ + * 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 DWORD ImbAsyncSeq; +/* + * This is the structure passed in to IOCTL_IMB_GET_ASYNC_MSG +*/ +typedef struct { + DWORD 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 <sys/types.h> +#define WRITE_READ_I2C 0x52 +#define WRITE_EMP_BUFFER 0x7a +#define GET_DEVICE_ID 0x1 +#define SEND_MESSAGE 0x34 +#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 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 + */ +/* + #define MIN_IMB_PACKET_SIZE 7 + #define MAX_IMB_PACKET_SIZE 33 +*/ +#define MAX_BUFFER_SIZE 64 +/*#endif // IMB_API */ +/****************************** + * FUNCTION PROTOTYPES + ******************************/ +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 (unsigned int eventId ); +ACCESN_STATUS +RegisterForImbAsyncMessageNotification (unsigned int *handleId); +ACCESN_STATUS +UnRegisterForImbAsyncMessageNotification (unsigned int handleId,int iFlag); +BYTE GetIpmiVersion(void); +#endif /* IMBAPI_H__ */ diff --git a/src/plugins/ipmi_intf.c b/src/plugins/ipmi_intf.c new file mode 100644 index 0000000..0fa76be --- /dev/null +++ b/src/plugins/ipmi_intf.c @@ -0,0 +1,651 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS) +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ifaddrs.h> +#include <unistd.h> +#include <netdb.h> +#endif + + +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_sdr.h> +#include <ipmitool/log.h> + +#define IPMI_DEFAULT_PAYLOAD_SIZE 25 + +#ifdef IPMI_INTF_OPEN +extern struct ipmi_intf ipmi_open_intf; +#endif +#ifdef IPMI_INTF_IMB +extern struct ipmi_intf ipmi_imb_intf; +#endif +#ifdef IPMI_INTF_LIPMI +extern struct ipmi_intf ipmi_lipmi_intf; +#endif +#ifdef IPMI_INTF_BMC +extern struct ipmi_intf ipmi_bmc_intf; +#endif +#ifdef IPMI_INTF_LAN +extern struct ipmi_intf ipmi_lan_intf; +#endif +#ifdef IPMI_INTF_LANPLUS +extern struct ipmi_intf ipmi_lanplus_intf; +#endif +#ifdef IPMI_INTF_FREE +extern struct ipmi_intf ipmi_free_intf; +#endif +#ifdef IPMI_INTF_SERIAL +extern struct ipmi_intf ipmi_serial_term_intf; +extern struct ipmi_intf ipmi_serial_bm_intf; +#endif +#ifdef IPMI_INTF_DUMMY +extern struct ipmi_intf ipmi_dummy_intf; +#endif + +struct ipmi_intf * ipmi_intf_table[] = { +#ifdef IPMI_INTF_OPEN + &ipmi_open_intf, +#endif +#ifdef IPMI_INTF_IMB + &ipmi_imb_intf, +#endif +#ifdef IPMI_INTF_LIPMI + &ipmi_lipmi_intf, +#endif +#ifdef IPMI_INTF_BMC + &ipmi_bmc_intf, +#endif +#ifdef IPMI_INTF_LAN + &ipmi_lan_intf, +#endif +#ifdef IPMI_INTF_LANPLUS + &ipmi_lanplus_intf, +#endif +#ifdef IPMI_INTF_FREE + &ipmi_free_intf, +#endif +#ifdef IPMI_INTF_SERIAL + &ipmi_serial_term_intf, + &ipmi_serial_bm_intf, +#endif +#ifdef IPMI_INTF_DUMMY + &ipmi_dummy_intf, +#endif + NULL +}; + +/* ipmi_intf_print - Print list of interfaces + * + * no meaningful return code + */ +void ipmi_intf_print(struct ipmi_intf_support * intflist) +{ + struct ipmi_intf ** intf; + struct ipmi_intf_support * sup; + int def = 1; + int found; + + lprintf(LOG_NOTICE, "Interfaces:"); + + for (intf = ipmi_intf_table; intf && *intf; intf++) { + + if (intflist != NULL) { + found = 0; + for (sup=intflist; sup->name != NULL; sup++) { + if (strncmp(sup->name, (*intf)->name, strlen(sup->name)) == 0 && + strncmp(sup->name, (*intf)->name, strlen((*intf)->name)) == 0 && + sup->supported == 1) + found = 1; + } + if (found == 0) + continue; + } + + lprintf(LOG_NOTICE, "\t%-12s %s %s", + (*intf)->name, (*intf)->desc, + def ? "[default]" : ""); + def = 0; + } + lprintf(LOG_NOTICE, ""); +} + +/* ipmi_intf_load - Load an interface from the interface table above + * If no interface name is given return first entry + * + * @name: interface name to try and load + * + * returns pointer to inteface structure if found + * returns NULL on error + */ +struct ipmi_intf * ipmi_intf_load(char * name) +{ + struct ipmi_intf ** intf; + struct ipmi_intf * i; + + if (name == NULL) { + i = ipmi_intf_table[0]; + if (i->setup != NULL && (i->setup(i) < 0)) { + lprintf(LOG_ERR, "Unable to setup " + "interface %s", name); + return NULL; + } + return i; + } + + for (intf = ipmi_intf_table; + ((intf != NULL) && (*intf != NULL)); + intf++) { + i = *intf; + if (strncmp(name, i->name, strlen(name)) == 0) { + if (i->setup != NULL && (i->setup(i) < 0)) { + lprintf(LOG_ERR, "Unable to setup " + "interface %s", name); + return NULL; + } + return i; + } + } + + return NULL; +} + +void +ipmi_intf_session_set_hostname(struct ipmi_intf * intf, char * hostname) +{ + if (intf->session == NULL) + return; + + memset(intf->session->hostname, 0, 16); + + if (hostname != NULL) { + memcpy(intf->session->hostname, hostname, + __min(strlen(hostname), 64)); + } +} + +void +ipmi_intf_session_set_username(struct ipmi_intf * intf, char * username) +{ + if (intf->session == NULL) + return; + + memset(intf->session->username, 0, 17); + + if (username == NULL) + return; + + memcpy(intf->session->username, username, __min(strlen(username), 16)); +} + +void +ipmi_intf_session_set_password(struct ipmi_intf * intf, char * password) +{ + if (intf->session == NULL) + return; + + memset(intf->session->authcode, 0, IPMI_AUTHCODE_BUFFER_SIZE); + + if (password == NULL) { + intf->session->password = 0; + return; + } + + intf->session->password = 1; + memcpy(intf->session->authcode, password, + __min(strlen(password), IPMI_AUTHCODE_BUFFER_SIZE)); +} + +void +ipmi_intf_session_set_privlvl(struct ipmi_intf * intf, uint8_t level) +{ + if (intf->session == NULL) + return; + + intf->session->privlvl = level; +} + +void +ipmi_intf_session_set_lookupbit(struct ipmi_intf * intf, uint8_t lookupbit) +{ + if (intf->session == NULL) + return; + + intf->session->v2_data.lookupbit = lookupbit; +} + +void +ipmi_intf_session_set_cipher_suite_id(struct ipmi_intf * intf, uint8_t cipher_suite_id) +{ + if (intf->session == NULL) + return; + + intf->session->cipher_suite_id = cipher_suite_id; +} + +void +ipmi_intf_session_set_sol_escape_char(struct ipmi_intf * intf, char sol_escape_char) +{ + if (intf->session == NULL) + return; + + intf->session->sol_escape_char = sol_escape_char; +} + +void +ipmi_intf_session_set_kgkey(struct ipmi_intf * intf, char * kgkey) +{ + if (intf->session == NULL) + return; + + memset(intf->session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE); + + if (kgkey == NULL) + return; + + memcpy(intf->session->v2_data.kg, kgkey, + __min(strlen(kgkey), IPMI_KG_BUFFER_SIZE)); +} + +void +ipmi_intf_session_set_port(struct ipmi_intf * intf, int port) +{ + if (intf->session == NULL) + return; + + intf->session->port = port; +} + +void +ipmi_intf_session_set_authtype(struct ipmi_intf * intf, uint8_t authtype) +{ + if (intf->session == NULL) + return; + + /* clear password field if authtype NONE specified */ + if (authtype == IPMI_SESSION_AUTHTYPE_NONE) { + memset(intf->session->authcode, 0, IPMI_AUTHCODE_BUFFER_SIZE); + intf->session->password = 0; + } + + intf->session->authtype_set = authtype; +} + +void +ipmi_intf_session_set_timeout(struct ipmi_intf * intf, uint32_t timeout) +{ + if (intf->session == NULL) + return; + + intf->session->timeout = timeout; +} + +void +ipmi_intf_session_set_retry(struct ipmi_intf * intf, int retry) +{ + if (intf->session == NULL) + return; + + intf->session->retry = retry; +} + +void +ipmi_cleanup(struct ipmi_intf * intf) +{ + ipmi_sdr_list_empty(intf); +} + +#if defined(IPMI_INTF_LAN) || defined (IPMI_INTF_LANPLUS) +int +ipmi_intf_socket_connect(struct ipmi_intf * intf) +{ + struct ipmi_session *session; + + struct sockaddr_storage addr; + struct addrinfo hints; + struct addrinfo *rp0 = NULL, *rp; + char service[NI_MAXSERV]; + int rc; + + if (!intf || intf->session == NULL) { + return -1; + } + + session = intf->session; + + if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) { + lprintf(LOG_ERR, "No hostname specified!"); + return -1; + } + + /* open port to BMC */ + memset(&addr, 0, sizeof(addr)); + + sprintf(service, "%d", session->port); + /* Obtain address(es) matching host/port */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = 0; /* use AI_NUMERICSERV for no name resolution */ + hints.ai_protocol = IPPROTO_UDP; /* */ + + if (getaddrinfo(session->hostname, service, &hints, &rp0) != 0) { + lprintf(LOG_ERR, "Address lookup for %s failed", + session->hostname); + return -1; + } + + /* getaddrinfo() returns a list of address structures. + * Try each address until we successfully connect(2). + * If socket(2) (or connect(2)) fails, we (close the socket + * and) try the next address. + */ + + session->ai_family = AF_UNSPEC; + for (rp = rp0; rp != NULL; rp = rp->ai_next) { + /* We are only interested in IPv4 and IPv6 */ + if ((rp->ai_family != AF_INET6) && (rp->ai_family != AF_INET)) { + continue; + } + + intf->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (intf->fd == -1) { + continue; + } + + if (rp->ai_family == AF_INET) { + if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { + memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); + session->addrlen = rp->ai_addrlen; + session->ai_family = rp->ai_family; + break; /* Success */ + } + } else if (rp->ai_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)rp->ai_addr; + char hbuf[NI_MAXHOST]; + socklen_t len; + + /* The scope was specified on the command line e.g. with -H FE80::219:99FF:FEA0:BD95%eth0 */ + if (addr6->sin6_scope_id != 0) { + len = sizeof(struct sockaddr_in6); + if (getnameinfo((struct sockaddr *)addr6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) { + lprintf(LOG_DEBUG, "Trying address: %s scope=%d", + hbuf, + addr6->sin6_scope_id); + } + if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { + memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); + session->addrlen = rp->ai_addrlen; + session->ai_family = rp->ai_family; + break; /* Success */ + } + } else { + /* No scope specified, try to get this from the list of interfaces */ + struct ifaddrs *ifaddrs = NULL; + struct ifaddrs *ifa = NULL; + + if (getifaddrs(&ifaddrs) < 0) { + lprintf(LOG_ERR, "Interface address lookup for %s failed", + session->hostname); + break; + } + + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) { + continue; + } + + if (ifa->ifa_addr->sa_family == AF_INET6) { + struct sockaddr_in6 *tmp6 = (struct sockaddr_in6 *)ifa->ifa_addr; + + /* Skip unwanted addresses */ + if (IN6_IS_ADDR_MULTICAST(&tmp6->sin6_addr)) { + continue; + } + if (IN6_IS_ADDR_LOOPBACK(&tmp6->sin6_addr)) { + continue; + } + len = sizeof(struct sockaddr_in6); + if ( getnameinfo((struct sockaddr *)tmp6, len, hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0) { + lprintf(LOG_DEBUG, "Testing %s interface address: %s scope=%d", + ifa->ifa_name != NULL ? ifa->ifa_name : "???", + hbuf, + tmp6->sin6_scope_id); + } + + if (tmp6->sin6_scope_id != 0) { + addr6->sin6_scope_id = tmp6->sin6_scope_id; + } else { + /* + * No scope information in interface address information + * On some OS'es, getifaddrs() is returning out the 'kernel' representation + * of scoped addresses which stores the scope in the 3rd and 4th + * byte. See also this page: + * http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html + */ + if (IN6_IS_ADDR_LINKLOCAL(&tmp6->sin6_addr) + && (tmp6->sin6_addr.s6_addr16[1] != 0)) { + addr6->sin6_scope_id = ntohs(tmp6->sin6_addr.s6_addr16[1]); + } + } + + /* OK, now try to connect with the scope id from this interface address */ + if (addr6->sin6_scope_id != 0) { + if (connect(intf->fd, rp->ai_addr, rp->ai_addrlen) != -1) { + memcpy(&session->addr, rp->ai_addr, rp->ai_addrlen); + session->addrlen = rp->ai_addrlen; + session->ai_family = rp->ai_family; + lprintf(LOG_DEBUG, "Successful connected on %s interface with scope id %d", ifa->ifa_name, tmp6->sin6_scope_id); + break; /* Success */ + } + } + } + } + freeifaddrs(ifaddrs); + } + } + if (session->ai_family != AF_UNSPEC) { + break; + } + close(intf->fd); + intf->fd = -1; + } + + /* No longer needed */ + freeaddrinfo(rp0); + + return ((intf->fd != -1) ? 0 : -1); +} +#endif + +uint16_t +ipmi_intf_get_max_request_data_size(struct ipmi_intf * intf) +{ + int16_t size; + + size = intf->max_request_data_size; + + /* check if request size is not specified */ + if (!size) { + /* + * The IPMB standard overall message length for ‘non -bridging’ + * messages is specified as 32 bytes, maximum, including slave + * address. This sets the upper limit for typical IPMI messages. + * With the exception of messages used for bridging messages to + * other busses or interfaces (e.g. Master Write-Read and Send Message) + * IPMI messages should be designed to fit within this 32-byte maximum. + * In order to support bridging, the Master Write -Read and Send Message + * commands are allowed to exceed the 32-byte maximum transaction on IPMB + */ + + size = IPMI_DEFAULT_PAYLOAD_SIZE; + + /* check if message is forwarded */ + if (intf->target_addr && intf->target_addr != intf->my_addr) { + /* add Send Message request size */ + size += 8; + } + } + + /* check if message is forwarded */ + if (intf->target_addr && intf->target_addr != intf->my_addr) { + /* subtract send message request size */ + size -= 8; + + /* + * Check that forwarded request size is not greater + * than the default payload size. + */ + if (size > IPMI_DEFAULT_PAYLOAD_SIZE) { + size = IPMI_DEFAULT_PAYLOAD_SIZE; + } + + /* check for double bridging */ + if (intf->transit_addr && intf->transit_addr != intf->target_addr) { + /* subtract inner send message request size */ + size -= 8; + } + } + + /* check for underflow */ + if (size < 0) { + return 0; + } + + return size; +} + +uint16_t +ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf) +{ + int16_t size; + + size = intf->max_response_data_size; + + /* check if response size is not specified */ + if (!size) { + /* + * The IPMB standard overall message length for ‘non -bridging’ + * messages is specified as 32 bytes, maximum, including slave + * address. This sets the upper limit for typical IPMI messages. + * With the exception of messages used for bridging messages to + * other busses or interfaces (e.g. Master Write-Read and Send Message) + * IPMI messages should be designed to fit within this 32-byte maximum. + * In order to support bridging, the Master Write -Read and Send Message + * commands are allowed to exceed the 32-byte maximum transaction on IPMB + */ + + size = IPMI_DEFAULT_PAYLOAD_SIZE; /* response length with subtracted header and checksum byte */ + + /* check if message is forwarded */ + if (intf->target_addr && intf->target_addr != intf->my_addr) { + /* add Send Message header size */ + size += 7; + } + } + + /* check if message is forwarded */ + if (intf->target_addr && intf->target_addr != intf->my_addr) { + /* + * Some IPMI controllers like PICMG AMC Carriers embed responses + * to the forwarded messages into the Send Message response. + * In order to be sure that the response is not truncated, + * subtract the internal message header size. + */ + size -= 8; + + /* + * Check that forwarded response is not greater + * than the default payload size. + */ + if (size > IPMI_DEFAULT_PAYLOAD_SIZE) { + size = IPMI_DEFAULT_PAYLOAD_SIZE; + } + + /* check for double bridging */ + if (intf->transit_addr && intf->transit_addr != intf->target_addr) { + /* subtract inner send message header size */ + size -= 8; + } + } + + /* check for underflow */ + if (size < 0) { + return 0; + } + + return size; +} + +void +ipmi_intf_set_max_request_data_size(struct ipmi_intf * intf, uint16_t size) +{ + if (size < IPMI_DEFAULT_PAYLOAD_SIZE) { + lprintf(LOG_ERR, "Request size is too small (%d), leave default size", + size); + return; + } + + if (intf->set_max_request_data_size) { + intf->set_max_request_data_size(intf, size); + } else { + intf->max_request_data_size = size; + } +} + +void +ipmi_intf_set_max_response_data_size(struct ipmi_intf * intf, uint16_t size) +{ + if (size < IPMI_DEFAULT_PAYLOAD_SIZE - 1) { + lprintf(LOG_ERR, "Response size is too small (%d), leave default size", + size); + return; + } + + if (intf->set_max_response_data_size) { + intf->set_max_response_data_size(intf, size); + } else { + intf->max_response_data_size = size; + } +} diff --git a/src/plugins/lan/Makefile.am b/src/plugins/lan/Makefile.am new file mode 100644 index 0000000..70e320f --- /dev/null +++ b/src/plugins/lan/Makefile.am @@ -0,0 +1,39 @@ +# 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_lan.la +noinst_LTLIBRARIES = @INTF_LAN_LIB@ +libintf_lan_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_lan_la_SOURCES = lan.c lan.h asf.h rmcp.h auth.c auth.h md5.c md5.h + diff --git a/src/plugins/lan/Makefile.in b/src/plugins/lan/Makefile.in new file mode 100644 index 0000000..5674953 --- /dev/null +++ b/src/plugins/lan/Makefile.in @@ -0,0 +1,540 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/lan +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_lan_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_lan_la_OBJECTS = lan.lo auth.lo md5.lo +libintf_lan_la_OBJECTS = $(am_libintf_lan_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_lan_la_SOURCES) +DIST_SOURCES = $(libintf_lan_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_lan.la +noinst_LTLIBRARIES = @INTF_LAN_LIB@ +libintf_lan_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_lan_la_SOURCES = lan.c lan.h asf.h rmcp.h auth.c auth.h md5.c md5.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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/lan/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/lan/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_lan.la: $(libintf_lan_la_OBJECTS) $(libintf_lan_la_DEPENDENCIES) $(EXTRA_libintf_lan_la_DEPENDENCIES) + $(LINK) $(libintf_lan_la_OBJECTS) $(libintf_lan_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lan.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/lan/asf.h b/src/plugins/lan/asf.h new file mode 100644 index 0000000..ab36d6f --- /dev/null +++ b/src/plugins/lan/asf.h @@ -0,0 +1,75 @@ +/* + * 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_ASF_H +#define IPMI_ASF_H + +#include <ipmitool/helper.h> +#include "lan.h" + +#define ASF_RMCP_IANA 0x000011be + +#define ASF_TYPE_PING 0x80 +#define ASF_TYPE_PONG 0x40 + +static const struct valstr asf_type_vals[] __attribute__((unused)) = { + { 0x10, "Reset" }, + { 0x11, "Power-up" }, + { 0x12, "Unconditional Power-down" }, + { 0x13, "Power Cycle" }, + { 0x40, "Presence Pong" }, + { 0x41, "Capabilities Response" }, + { 0x42, "System State Response" }, + { 0x80, "Presence Ping" }, + { 0x81, "Capabilities Request" }, + { 0x82, "System State Request" }, + { 0x00, NULL } +}; + +/* ASF message header */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct asf_hdr { + uint32_t iana; + uint8_t type; + uint8_t tag; + uint8_t __reserved; + uint8_t len; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +int handle_asf(struct ipmi_intf * intf, uint8_t * data, int data_len); + +#endif /* IPMI_ASF_H */ diff --git a/src/plugins/lan/auth.c b/src/plugins/lan/auth.c new file mode 100644 index 0000000..7410e3c --- /dev/null +++ b/src/plugins/lan/auth.c @@ -0,0 +1,220 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include <ipmitool/helper.h> +#include <ipmitool/bswap.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_CRYPTO_MD2 +# include <openssl/md2.h> +#endif + +#ifdef HAVE_CRYPTO_MD5 +# include <openssl/md5.h> +#else +# include "md5.h" +#endif + +/* + * multi-session authcode generation for MD5 + * H(password + session_id + msg + session_seq + password) + * + * Use OpenSSL implementation of MD5 algorithm if found + */ +uint8_t * ipmi_auth_md5(struct ipmi_session * s, uint8_t * data, int data_len) +{ +#ifdef HAVE_CRYPTO_MD5 + MD5_CTX ctx; + static uint8_t md[16]; + uint32_t temp; + +#if WORDS_BIGENDIAN + temp = BSWAP_32(s->in_seq); +#else + temp = s->in_seq; +#endif + memset(md, 0, 16); + memset(&ctx, 0, sizeof(MD5_CTX)); + + MD5_Init(&ctx); + MD5_Update(&ctx, (const uint8_t *)s->authcode, 16); + MD5_Update(&ctx, (const uint8_t *)&s->session_id, 4); + MD5_Update(&ctx, (const uint8_t *)data, data_len); + MD5_Update(&ctx, (const uint8_t *)&temp, sizeof(uint32_t)); + MD5_Update(&ctx, (const uint8_t *)s->authcode, 16); + MD5_Final(md, &ctx); + + if (verbose > 3) + printf(" MD5 AuthCode : %s\n", buf2str(md, 16)); + + return md; +#else /*HAVE_CRYPTO_MD5*/ + md5_state_t state; + static md5_byte_t digest[16]; + uint32_t temp; + + memset(digest, 0, 16); + memset(&state, 0, sizeof(md5_state_t)); + + md5_init(&state); + + md5_append(&state, (const md5_byte_t *)s->authcode, 16); + md5_append(&state, (const md5_byte_t *)&s->session_id, 4); + md5_append(&state, (const md5_byte_t *)data, data_len); + +#if WORDS_BIGENDIAN + temp = BSWAP_32(s->in_seq); +#else + temp = s->in_seq; +#endif + md5_append(&state, (const md5_byte_t *)&temp, 4); + md5_append(&state, (const md5_byte_t *)s->authcode, 16); + + md5_finish(&state, digest); + + if (verbose > 3) + printf(" MD5 AuthCode : %s\n", buf2str(digest, 16)); + return digest; +#endif /*HAVE_CRYPTO_MD5*/ +} + +/* + * multi-session authcode generation for MD2 + * H(password + session_id + msg + session_seq + password) + * + * Use OpenSSL implementation of MD2 algorithm if found. + * This function is analogous to ipmi_auth_md5 + */ +uint8_t * ipmi_auth_md2(struct ipmi_session * s, uint8_t * data, int data_len) +{ +#ifdef HAVE_CRYPTO_MD2 + MD2_CTX ctx; + static uint8_t md[16]; + uint32_t temp; + +#if WORDS_BIGENDIAN + temp = BSWAP_32(s->in_seq); +#else + temp = s->in_seq; +#endif + memset(md, 0, 16); + memset(&ctx, 0, sizeof(MD2_CTX)); + + MD2_Init(&ctx); + MD2_Update(&ctx, (const uint8_t *)s->authcode, 16); + MD2_Update(&ctx, (const uint8_t *)&s->session_id, 4); + MD2_Update(&ctx, (const uint8_t *)data, data_len); + MD2_Update(&ctx, (const uint8_t *)&temp, sizeof(uint32_t)); + MD2_Update(&ctx, (const uint8_t *)s->authcode, 16); + MD2_Final(md, &ctx); + + if (verbose > 3) + printf(" MD2 AuthCode : %s\n", buf2str(md, 16)); + + return md; +#else /*HAVE_CRYPTO_MD2*/ + static uint8_t md[16]; + memset(md, 0, 16); + printf("WARNING: No internal support for MD2! " + "Please re-compile with OpenSSL.\n"); + return md; +#endif /*HAVE_CRYPTO_MD2*/ +} + +/* special authentication method */ +uint8_t * ipmi_auth_special(struct ipmi_session * s) +{ +#ifdef HAVE_CRYPTO_MD5 + MD5_CTX ctx; + static uint8_t md[16]; + uint8_t challenge[16]; + int i; + + memset(challenge, 0, 16); + memset(md, 0, 16); + memset(&ctx, 0, sizeof(MD5_CTX)); + + MD5_Init(&ctx); + MD5_Update(&ctx, (const uint8_t *)s->authcode, strlen((const char *)s->authcode)); + MD5_Final(md, &ctx); + + for (i=0; i<16; i++) + challenge[i] = s->challenge[i] ^ md[i]; + + memset(md, 0, 16); + memset(&ctx, 0, sizeof(MD5_CTX)); + + MD5_Init(&ctx); + MD5_Update(&ctx, (const uint8_t *)challenge, 16); + MD5_Final(md, &ctx); + + return md; +#else /*HAVE_CRYPTO_MD5*/ + int i; + md5_state_t state; + static md5_byte_t digest[16]; + uint8_t challenge[16]; + + memset(challenge, 0, 16); + memset(digest, 0, 16); + memset(&state, 0, sizeof(md5_state_t)); + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)s->authcode, strlen(s->authcode)); + md5_finish(&state, digest); + + for (i=0; i<16; i++) + challenge[i] = s->challenge[i] ^ digest[i]; + + memset(digest, 0, 16); + memset(&state, 0, sizeof(md5_state_t)); + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)challenge, 16); + md5_finish(&state, digest); + + return digest; +#endif /*HAVE_CRYPTO_MD5*/ +} + diff --git a/src/plugins/lan/auth.h b/src/plugins/lan/auth.h new file mode 100644 index 0000000..b9866ba --- /dev/null +++ b/src/plugins/lan/auth.h @@ -0,0 +1,40 @@ +/* + * 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_AUTH_H +#define IPMI_AUTH_H + +uint8_t * ipmi_auth_md2(struct ipmi_session * s, uint8_t * data, int data_len); +uint8_t * ipmi_auth_md5(struct ipmi_session * s, uint8_t * data, int data_len); +uint8_t * ipmi_auth_special(struct ipmi_session * s); + +#endif /*IPMI_AUTH_H*/ diff --git a/src/plugins/lan/lan.c b/src/plugins/lan/lan.c new file mode 100644 index 0000000..fb1a633 --- /dev/null +++ b/src/plugins/lan/lan.c @@ -0,0 +1,2112 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <unistd.h> +#include <netdb.h> +#include <fcntl.h> + +#include <ipmitool/helper.h> +#include <ipmitool/log.h> +#include <ipmitool/bswap.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_sel.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_oem.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/ipmi_constants.h> +#include <ipmitool/hpm2.h> + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include "lan.h" +#include "rmcp.h" +#include "asf.h" +#include "auth.h" + +#define IPMI_LAN_TIMEOUT 2 +#define IPMI_LAN_RETRY 4 +#define IPMI_LAN_PORT 0x26f +#define IPMI_LAN_CHANNEL_E 0x0e + +/* + * LAN interface is required to support 45 byte request transactions and + * 42 byte response transactions. + */ +#define IPMI_LAN_MAX_REQUEST_SIZE 38 /* 45 - 7 */ +#define IPMI_LAN_MAX_RESPONSE_SIZE 34 /* 42 - 8 */ + +extern const struct valstr ipmi_privlvl_vals[]; +extern const struct valstr ipmi_authtype_session_vals[]; +extern int verbose; + +struct ipmi_rq_entry * ipmi_req_entries; +static struct ipmi_rq_entry * ipmi_req_entries_tail; +static uint8_t bridge_possible = 0; + +static int ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len); +static struct ipmi_rs * ipmi_lan_recv_packet(struct ipmi_intf * intf); +static struct ipmi_rs * ipmi_lan_poll_recv(struct ipmi_intf * intf); +static int ipmi_lan_setup(struct ipmi_intf * intf); +static int ipmi_lan_keepalive(struct ipmi_intf * intf); +static struct ipmi_rs * ipmi_lan_recv_sol(struct ipmi_intf * intf); +static struct ipmi_rs * ipmi_lan_send_sol(struct ipmi_intf * intf, + struct ipmi_v2_payload * payload); +static struct ipmi_rs * ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req); +static int ipmi_lan_send_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp); +static int ipmi_lan_open(struct ipmi_intf * intf); +static void ipmi_lan_close(struct ipmi_intf * intf); +static int ipmi_lan_ping(struct ipmi_intf * intf); +static void ipmi_lan_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size); +static void ipmi_lan_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size); + +struct ipmi_intf ipmi_lan_intf = { + name: "lan", + desc: "IPMI v1.5 LAN Interface", + setup: ipmi_lan_setup, + open: ipmi_lan_open, + close: ipmi_lan_close, + sendrecv: ipmi_lan_send_cmd, + sendrsp: ipmi_lan_send_rsp, + recv_sol: ipmi_lan_recv_sol, + send_sol: ipmi_lan_send_sol, + keepalive: ipmi_lan_keepalive, + set_max_request_data_size: ipmi_lan_set_max_rq_data_size, + set_max_response_data_size: ipmi_lan_set_max_rp_data_size, + target_addr: IPMI_BMC_SLAVE_ADDR, +}; + +static struct ipmi_rq_entry * +ipmi_req_add_entry(struct ipmi_intf * intf, struct ipmi_rq * req, uint8_t req_seq) +{ + struct ipmi_rq_entry * e; + + e = malloc(sizeof(struct ipmi_rq_entry)); + if (e == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + + memset(e, 0, sizeof(struct ipmi_rq_entry)); + memcpy(&e->req, req, sizeof(struct ipmi_rq)); + + e->intf = intf; + e->rq_seq = req_seq; + + if (ipmi_req_entries == NULL) + ipmi_req_entries = e; + else + ipmi_req_entries_tail->next = e; + + ipmi_req_entries_tail = e; + lprintf(LOG_DEBUG+3, "added list entry seq=0x%02x cmd=0x%02x", + e->rq_seq, e->req.msg.cmd); + return e; +} + +static struct ipmi_rq_entry * +ipmi_req_lookup_entry(uint8_t seq, uint8_t cmd) +{ + struct ipmi_rq_entry * e = ipmi_req_entries; + while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) { + if (e->next == NULL || e == e->next) + return NULL; + e = e->next; + } + return e; +} + +static void +ipmi_req_remove_entry(uint8_t seq, uint8_t cmd) +{ + struct ipmi_rq_entry * p, * e, * saved_next_entry; + + e = p = ipmi_req_entries; + + while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) { + p = e; + e = e->next; + } + if (e) { + lprintf(LOG_DEBUG+3, "removed list entry seq=0x%02x cmd=0x%02x", + seq, cmd); + saved_next_entry = e->next; + p->next = (p->next == e->next) ? NULL : e->next; + /* If entry being removed is first in list, fix up list head */ + if (ipmi_req_entries == e) { + if (ipmi_req_entries != p) + ipmi_req_entries = p; + else + ipmi_req_entries = saved_next_entry; + } + /* If entry being removed is last in list, fix up list tail */ + if (ipmi_req_entries_tail == e) { + if (ipmi_req_entries_tail != p) + ipmi_req_entries_tail = p; + else + ipmi_req_entries_tail = NULL; + } + if (e->msg_data) { + free(e->msg_data); + e->msg_data = NULL; + } + free(e); + e = NULL; + } +} + +static void +ipmi_req_clear_entries(void) +{ + struct ipmi_rq_entry * p, * e; + + e = ipmi_req_entries; + while (e) { + lprintf(LOG_DEBUG+3, "cleared list entry seq=0x%02x cmd=0x%02x", + e->rq_seq, e->req.msg.cmd); + if (e->next != NULL) { + p = e->next; + free(e); + e = p; + } else { + free(e); + e = NULL; + break; + } + } + ipmi_req_entries = NULL; +} + +static int +get_random(void *data, int len) +{ + int fd = open("/dev/urandom", O_RDONLY); + int rv; + + if (fd < 0) + return errno; + if (len < 0) { + close(fd); + return errno; /* XXX: ORLY? */ + } + + rv = read(fd, data, len); + + close(fd); + return rv; +} + +static int +ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len) +{ + if (verbose > 2) + printbuf(data, data_len, "send_packet"); + + return send(intf->fd, data, data_len, 0); +} + +static struct ipmi_rs * +ipmi_lan_recv_packet(struct ipmi_intf * intf) +{ + static struct ipmi_rs rsp; + fd_set read_set, err_set; + struct timeval tmout; + int ret; + + FD_ZERO(&read_set); + FD_SET(intf->fd, &read_set); + + FD_ZERO(&err_set); + FD_SET(intf->fd, &err_set); + + tmout.tv_sec = intf->session->timeout; + tmout.tv_usec = 0; + + ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout); + if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) + return NULL; + + /* the first read may return ECONNREFUSED because the rmcp ping + * packet--sent to UDP port 623--will be processed by both the + * BMC and the OS. + * + * The problem with this is that the ECONNREFUSED takes + * priority over any other received datagram; that means that + * the Connection Refused shows up _before_ the response packet, + * regardless of the order they were sent out. (unless the + * response is read before the connection refused is returned) + */ + ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); + + if (ret < 0) { + FD_ZERO(&read_set); + FD_SET(intf->fd, &read_set); + + FD_ZERO(&err_set); + FD_SET(intf->fd, &err_set); + + tmout.tv_sec = intf->session->timeout; + tmout.tv_usec = 0; + + ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout); + if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) + return NULL; + + ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); + if (ret < 0) + return NULL; + } + + if (ret == 0) + return NULL; + + rsp.data[ret] = '\0'; + rsp.data_len = ret; + + if (verbose > 2) + printbuf(rsp.data, rsp.data_len, "recv_packet"); + + return &rsp; +} + +/* + * parse response RMCP "pong" packet + * + * return -1 if ping response not received + * returns 0 if IPMI is NOT supported + * returns 1 if IPMI is supported + * + * udp.source = 0x026f // RMCP_UDP_PORT + * udp.dest = ? // udp.source from rmcp-ping + * udp.len = ? + * udp.check = ? + * rmcp.ver = 0x06 // RMCP Version 1.0 + * rmcp.__res = 0x00 // RESERVED + * rmcp.seq = 0xff // no RMCP ACK + * rmcp.class = 0x06 // RMCP_CLASS_ASF + * asf.iana = 0x000011be // ASF_RMCP_IANA + * asf.type = 0x40 // ASF_TYPE_PONG + * asf.tag = ? // asf.tag from rmcp-ping + * asf.__res = 0x00 // RESERVED + * asf.len = 0x10 // 16 bytes + * asf.data[3:0]= 0x000011be // IANA# = RMCP_ASF_IANA if no OEM + * asf.data[7:4]= 0x00000000 // OEM-defined (not for IPMI) + * asf.data[8] = 0x81 // supported entities + * // [7]=IPMI [6:4]=RES [3:0]=ASF_1.0 + * asf.data[9] = 0x00 // supported interactions (reserved) + * asf.data[f:a]= 0x000000000000 + */ +static int +ipmi_handle_pong(struct ipmi_intf * intf, struct ipmi_rs * rsp) +{ + struct rmcp_pong * pong; + + if (rsp == NULL) + return -1; + + pong = (struct rmcp_pong *)rsp->data; + + lprintf(LOG_DEBUG, + "Received IPMI/RMCP response packet: \n" + " IPMI%s Supported\n" + " ASF Version %s\n" + " RMCP Version %s\n" + " RMCP Sequence %d\n" + " IANA Enterprise %ld\n", + (pong->sup_entities & 0x80) ? "" : " NOT", + (pong->sup_entities & 0x01) ? "1.0" : "unknown", + (pong->rmcp.ver == 6) ? "1.0" : "unknown", + pong->rmcp.seq, + ntohl(pong->iana)); + + return (pong->sup_entities & 0x80) ? 1 : 0; +} + +/* build and send RMCP presence ping packet + * + * RMCP ping + * + * udp.source = ? + * udp.dest = 0x026f // RMCP_UDP_PORT + * udp.len = ? + * udp.check = ? + * rmcp.ver = 0x06 // RMCP Version 1.0 + * rmcp.__res = 0x00 // RESERVED + * rmcp.seq = 0xff // no RMCP ACK + * rmcp.class = 0x06 // RMCP_CLASS_ASF + * asf.iana = 0x000011be // ASF_RMCP_IANA + * asf.type = 0x80 // ASF_TYPE_PING + * asf.tag = ? // ASF sequence number + * asf.__res = 0x00 // RESERVED + * asf.len = 0x00 + * + */ +static int +ipmi_lan_ping(struct ipmi_intf * intf) +{ + struct asf_hdr asf_ping = { + .iana = htonl(ASF_RMCP_IANA), + .type = ASF_TYPE_PING, + }; + struct rmcp_hdr rmcp_ping = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_ASF, + .seq = 0xff, + }; + uint8_t * data; + int len = sizeof(rmcp_ping) + sizeof(asf_ping); + int rv; + + data = malloc(len); + if (data == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + memset(data, 0, len); + memcpy(data, &rmcp_ping, sizeof(rmcp_ping)); + memcpy(data+sizeof(rmcp_ping), &asf_ping, sizeof(asf_ping)); + + lprintf(LOG_DEBUG, "Sending IPMI/RMCP presence ping packet"); + + rv = ipmi_lan_send_packet(intf, data, len); + + free(data); + data = NULL; + + if (rv < 0) { + lprintf(LOG_ERR, "Unable to send IPMI presence ping packet"); + return -1; + } + + if (ipmi_lan_poll_recv(intf) == 0) + return 0; + + return 1; +} + +/* + * The "thump" functions are used to send an extra packet following each + * request message. This may kick-start some BMCs that get confused with + * bad passwords or operate poorly under heavy network load. + */ +static void +ipmi_lan_thump_first(struct ipmi_intf * intf) +{ + /* is this random data? */ + uint8_t data[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x20, 0x18, 0xc8, 0xc2, 0x01, 0x01, 0x3c }; + ipmi_lan_send_packet(intf, data, 16); +} + +static void +ipmi_lan_thump(struct ipmi_intf * intf) +{ + uint8_t data[10] = "thump"; + ipmi_lan_send_packet(intf, data, 10); +} + +static struct ipmi_rs * +ipmi_lan_poll_recv(struct ipmi_intf * intf) +{ + struct rmcp_hdr rmcp_rsp; + struct ipmi_rs * rsp; + struct ipmi_rq_entry * entry; + int x=0, rv; + uint8_t our_address = intf->my_addr; + + if (our_address == 0) + our_address = IPMI_BMC_SLAVE_ADDR; + + rsp = ipmi_lan_recv_packet(intf); + + while (rsp != NULL) { + + /* parse response headers */ + memcpy(&rmcp_rsp, rsp->data, 4); + + switch (rmcp_rsp.class) { + case RMCP_CLASS_ASF: + /* ping response packet */ + rv = ipmi_handle_pong(intf, rsp); + return (rv <= 0) ? NULL : rsp; + case RMCP_CLASS_IPMI: + /* handled by rest of function */ + break; + default: + lprintf(LOG_DEBUG, "Invalid RMCP class: %x", + rmcp_rsp.class); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + x = 4; + rsp->session.authtype = rsp->data[x++]; + memcpy(&rsp->session.seq, rsp->data+x, 4); + x += 4; + memcpy(&rsp->session.id, rsp->data+x, 4); + x += 4; + + if (rsp->session.id == (intf->session->session_id + 0x10000000)) { + /* With SOL, authtype is always NONE, so we have no authcode */ + rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_SOL; + + rsp->session.msglen = rsp->data[x++]; + + rsp->payload.sol_packet.packet_sequence_number = + rsp->data[x++] & 0x0F; + + rsp->payload.sol_packet.acked_packet_number = + rsp->data[x++] & 0x0F; + + rsp->payload.sol_packet.accepted_character_count = + rsp->data[x++]; + + rsp->payload.sol_packet.is_nack = + rsp->data[x] & 0x40; + + rsp->payload.sol_packet.transfer_unavailable = + rsp->data[x] & 0x20; + + rsp->payload.sol_packet.sol_inactive = + rsp->data[x] & 0x10; + + rsp->payload.sol_packet.transmit_overrun = + rsp->data[x] & 0x08; + + rsp->payload.sol_packet.break_detected = + rsp->data[x++] & 0x04; + + x++; /* On ISOL there's and additional fifth byte before the data starts */ + + lprintf(LOG_DEBUG, "SOL sequence number : 0x%02x", + rsp->payload.sol_packet.packet_sequence_number); + + lprintf(LOG_DEBUG, "SOL acked packet : 0x%02x", + rsp->payload.sol_packet.acked_packet_number); + + lprintf(LOG_DEBUG, "SOL accepted char count : 0x%02x", + rsp->payload.sol_packet.accepted_character_count); + + lprintf(LOG_DEBUG, "SOL is nack : %s", + rsp->payload.sol_packet.is_nack? "true" : "false"); + + lprintf(LOG_DEBUG, "SOL xfer unavailable : %s", + rsp->payload.sol_packet.transfer_unavailable? "true" : "false"); + + lprintf(LOG_DEBUG, "SOL inactive : %s", + rsp->payload.sol_packet.sol_inactive? "true" : "false"); + + lprintf(LOG_DEBUG, "SOL transmit overrun : %s", + rsp->payload.sol_packet.transmit_overrun? "true" : "false"); + + lprintf(LOG_DEBUG, "SOL break detected : %s", + rsp->payload.sol_packet.break_detected? "true" : "false"); + } + else + { + /* Standard IPMI 1.5 packet */ + rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_IPMI; + if (intf->session->active && (rsp->session.authtype || intf->session->authtype)) + x += 16; + + rsp->session.msglen = rsp->data[x++]; + rsp->payload.ipmi_response.rq_addr = rsp->data[x++]; + rsp->payload.ipmi_response.netfn = rsp->data[x] >> 2; + rsp->payload.ipmi_response.rq_lun = rsp->data[x++] & 0x3; + x++; /* checksum */ + rsp->payload.ipmi_response.rs_addr = rsp->data[x++]; + rsp->payload.ipmi_response.rq_seq = rsp->data[x] >> 2; + rsp->payload.ipmi_response.rs_lun = rsp->data[x++] & 0x3; + rsp->payload.ipmi_response.cmd = rsp->data[x++]; + rsp->ccode = rsp->data[x++]; + + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "ipmi message header"); + + lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header"); + lprintf(LOG_DEBUG+1, "<< Authtype : %s", + val2str(rsp->session.authtype, ipmi_authtype_session_vals)); + lprintf(LOG_DEBUG+1, "<< Sequence : 0x%08lx", + (long)rsp->session.seq); + lprintf(LOG_DEBUG+1, "<< Session ID : 0x%08lx", + (long)rsp->session.id); + lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header"); + lprintf(LOG_DEBUG+1, "<< Rq Addr : %02x", + rsp->payload.ipmi_response.rq_addr); + lprintf(LOG_DEBUG+1, "<< NetFn : %02x", + rsp->payload.ipmi_response.netfn); + lprintf(LOG_DEBUG+1, "<< Rq LUN : %01x", + rsp->payload.ipmi_response.rq_lun); + lprintf(LOG_DEBUG+1, "<< Rs Addr : %02x", + rsp->payload.ipmi_response.rs_addr); + lprintf(LOG_DEBUG+1, "<< Rq Seq : %02x", + rsp->payload.ipmi_response.rq_seq); + lprintf(LOG_DEBUG+1, "<< Rs Lun : %01x", + rsp->payload.ipmi_response.rs_lun); + lprintf(LOG_DEBUG+1, "<< Command : %02x", + rsp->payload.ipmi_response.cmd); + lprintf(LOG_DEBUG+1, "<< Compl Code : 0x%02x", + rsp->ccode); + + /* now see if we have outstanding entry in request list */ + entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq, + rsp->payload.ipmi_response.cmd); + if (entry) { + lprintf(LOG_DEBUG+2, "IPMI Request Match found"); + if ((intf->target_addr != our_address) && bridge_possible) { + if ((rsp->data_len) && (rsp->payload.ipmi_response.netfn == 7) && + (rsp->payload.ipmi_response.cmd != 0x34)) { + if (verbose > 2) + printbuf(&rsp->data[x], rsp->data_len-x, + "bridge command response"); + } + /* bridged command: lose extra header */ + if (entry->bridging_level && + rsp->payload.ipmi_response.netfn == 7 && + rsp->payload.ipmi_response.cmd == 0x34) { + entry->bridging_level--; + if (rsp->data_len - x - 1 == 0) { + rsp = !rsp->ccode ? ipmi_lan_recv_packet(intf) : NULL; + if (!entry->bridging_level) + entry->req.msg.cmd = entry->req.msg.target_cmd; + if (rsp == NULL) { + ipmi_req_remove_entry(entry->rq_seq, entry->req.msg.cmd); + } + continue; + } else { + /* The bridged answer data are inside the incoming packet */ + memmove(rsp->data + x - 7, + rsp->data + x, + rsp->data_len - x - 1); + rsp->data[x - 8] -= 8; + rsp->data_len -= 8; + entry->rq_seq = rsp->data[x - 3] >> 2; + if (!entry->bridging_level) + entry->req.msg.cmd = entry->req.msg.target_cmd; + continue; + } + } else { + //x += sizeof(rsp->payload.ipmi_response); + if (rsp->data[x-1] != 0) + lprintf(LOG_DEBUG, "WARNING: Bridged " + "cmd ccode = 0x%02x", + rsp->data[x-1]); + } + } + ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq, + rsp->payload.ipmi_response.cmd); + } else { + lprintf(LOG_INFO, "IPMI Request Match NOT FOUND"); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + } + + break; + } + + /* shift response data to start of array */ + if (rsp && rsp->data_len > x) { + rsp->data_len -= x; + if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI) + rsp->data_len -= 1; /* We don't want the checksum */ + memmove(rsp->data, rsp->data + x, rsp->data_len); + memset(rsp->data + rsp->data_len, 0, IPMI_BUF_SIZE - rsp->data_len); + } + + return rsp; +} + +/* + * IPMI LAN Request Message Format + * +--------------------+ + * | rmcp.ver | 4 bytes + * | rmcp.__reserved | + * | rmcp.seq | + * | rmcp.class | + * +--------------------+ + * | session.authtype | 9 bytes + * | session.seq | + * | session.id | + * +--------------------+ + * | [session.authcode] | 16 bytes (AUTHTYPE != none) + * +--------------------+ + * | message length | 1 byte + * +--------------------+ + * | message.rs_addr | 6 bytes + * | message.netfn_lun | + * | message.checksum | + * | message.rq_addr | + * | message.rq_seq | + * | message.cmd | + * +--------------------+ + * | [request data] | data_len bytes + * +--------------------+ + * | checksum | 1 byte + * +--------------------+ + */ +static struct ipmi_rq_entry * +ipmi_lan_build_cmd(struct ipmi_intf * intf, struct ipmi_rq * req, int isRetry) +{ + struct rmcp_hdr rmcp = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_IPMI, + .seq = 0xff, + }; + uint8_t * msg, * temp; + int cs, mp, tmp; + int ap = 0; + int len = 0; + int cs2 = 0, cs3 = 0; + struct ipmi_rq_entry * entry; + struct ipmi_session * s = intf->session; + static int curr_seq = 0; + uint8_t our_address = intf->my_addr; + + if (our_address == 0) + our_address = IPMI_BMC_SLAVE_ADDR; + + if (isRetry == 0) + curr_seq++; + + if (curr_seq >= 64) + curr_seq = 0; + + // Bug in the existing code where it keeps on adding same command/seq pair + // in the lookup entry list. + // Check if we have cmd,seq pair already in our list. As we are not changing + // the seq number we have to re-use the node which has existing + // command and sequence number. If we add then we will have redundant node with + // same cmd,seq pair + entry = ipmi_req_lookup_entry(curr_seq, req->msg.cmd); + if (entry) + { + // This indicates that we have already same command and seq in list + // No need to add once again and we will re-use the existing node. + // Only thing we have to do is clear the msg_data as we create + // a new one below in the code for it. + if (entry->msg_data) { + free(entry->msg_data); + entry->msg_data = NULL; + } + } + else + { + // We dont have this request in the list so we can add it + // to the list + entry = ipmi_req_add_entry(intf, req, curr_seq); + if (entry == NULL) + return NULL; + } + + len = req->msg.data_len + 29; + if (s->active && s->authtype) + len += 16; + if (intf->transit_addr != intf->my_addr && intf->transit_addr != 0) + len += 8; + msg = malloc(len); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + memset(msg, 0, len); + + /* rmcp header */ + memcpy(msg, &rmcp, sizeof(rmcp)); + len = sizeof(rmcp); + + /* ipmi session header */ + msg[len++] = s->active ? s->authtype : 0; + + msg[len++] = s->in_seq & 0xff; + msg[len++] = (s->in_seq >> 8) & 0xff; + msg[len++] = (s->in_seq >> 16) & 0xff; + msg[len++] = (s->in_seq >> 24) & 0xff; + memcpy(msg+len, &s->session_id, 4); + len += 4; + + /* ipmi session authcode */ + if (s->active && s->authtype) { + ap = len; + memcpy(msg+len, s->authcode, 16); + len += 16; + } + + /* message length */ + if ((intf->target_addr == our_address) || !bridge_possible) { + entry->bridging_level = 0; + msg[len++] = req->msg.data_len + 7; + cs = mp = len; + } else { + /* bridged request: encapsulate w/in Send Message */ + entry->bridging_level = 1; + msg[len++] = req->msg.data_len + 15 + + (intf->transit_addr != intf->my_addr && intf->transit_addr != 0 ? 8 : 0); + cs = mp = len; + msg[len++] = IPMI_BMC_SLAVE_ADDR; + msg[len++] = IPMI_NETFN_APP << 2; + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs2 = len; + msg[len++] = IPMI_REMOTE_SWID; + msg[len++] = curr_seq << 2; + msg[len++] = 0x34; /* Send Message rqst */ + entry->req.msg.target_cmd = entry->req.msg.cmd; /* Save target command */ + entry->req.msg.cmd = 0x34; /* (fixup request entry) */ + + if (intf->transit_addr == intf->my_addr || intf->transit_addr == 0) { + msg[len++] = (0x40|intf->target_channel); /* Track request*/ + } else { + entry->bridging_level++; + msg[len++] = (0x40|intf->transit_channel); /* Track request*/ + cs = len; + msg[len++] = intf->transit_addr; + msg[len++] = IPMI_NETFN_APP << 2; + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs3 = len; + msg[len++] = intf->my_addr; + msg[len++] = curr_seq << 2; + msg[len++] = 0x34; /* Send Message rqst */ + msg[len++] = (0x40|intf->target_channel); /* Track request */ + } + cs = len; + } + + /* ipmi message header */ + msg[len++] = intf->target_addr; + msg[len++] = req->msg.netfn << 2 | (req->msg.lun & 3); + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs = len; + + if (!entry->bridging_level) + msg[len++] = IPMI_REMOTE_SWID; + /* Bridged message */ + else if (entry->bridging_level) + msg[len++] = intf->my_addr; + + entry->rq_seq = curr_seq; + msg[len++] = entry->rq_seq << 2; + msg[len++] = req->msg.cmd; + + lprintf(LOG_DEBUG+1, ">> IPMI Request Session Header (level %d)", entry->bridging_level); + lprintf(LOG_DEBUG+1, ">> Authtype : %s", + val2str(s->authtype, ipmi_authtype_session_vals)); + lprintf(LOG_DEBUG+1, ">> Sequence : 0x%08lx", (long)s->in_seq); + lprintf(LOG_DEBUG+1, ">> Session ID : 0x%08lx", (long)s->session_id); + lprintf(LOG_DEBUG+1, ">> IPMI Request Message Header"); + lprintf(LOG_DEBUG+1, ">> Rs Addr : %02x", intf->target_addr); + lprintf(LOG_DEBUG+1, ">> NetFn : %02x", req->msg.netfn); + lprintf(LOG_DEBUG+1, ">> Rs LUN : %01x", 0); + lprintf(LOG_DEBUG+1, ">> Rq Addr : %02x", IPMI_REMOTE_SWID); + lprintf(LOG_DEBUG+1, ">> Rq Seq : %02x", entry->rq_seq); + lprintf(LOG_DEBUG+1, ">> Rq Lun : %01x", 0); + lprintf(LOG_DEBUG+1, ">> Command : %02x", req->msg.cmd); + + /* message data */ + if (req->msg.data_len) { + memcpy(msg+len, req->msg.data, req->msg.data_len); + len += req->msg.data_len; + } + + /* second checksum */ + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + + /* bridged request: 2nd checksum */ + if (entry->bridging_level) { + if (intf->transit_addr != intf->my_addr && intf->transit_addr != 0) { + tmp = len - cs3; + msg[len++] = ipmi_csum(msg+cs3, tmp); + } + tmp = len - cs2; + msg[len++] = ipmi_csum(msg+cs2, tmp); + } + + if (s->active) { + /* + * s->authcode is already copied to msg+ap but some + * authtypes require portions of the ipmi message to + * create the authcode so they must be done last. + */ + switch (s->authtype) { + case IPMI_SESSION_AUTHTYPE_MD5: + temp = ipmi_auth_md5(s, msg+mp, msg[mp-1]); + memcpy(msg+ap, temp, 16); + break; + case IPMI_SESSION_AUTHTYPE_MD2: + temp = ipmi_auth_md2(s, msg+mp, msg[mp-1]); + memcpy(msg+ap, temp, 16); + break; + } + } + + if (s->in_seq) { + s->in_seq++; + if (s->in_seq == 0) + s->in_seq++; + } + + entry->msg_len = len; + entry->msg_data = msg; + + return entry; +} + +static struct ipmi_rs * +ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + struct ipmi_rq_entry * entry; + struct ipmi_rs * rsp = NULL; + int try = 0; + int isRetry = 0; + + lprintf(LOG_DEBUG, "ipmi_lan_send_cmd:opened=[%d], open=[%d]", + intf->opened, intf->open); + + if (intf->opened == 0 && intf->open != NULL) { + if (intf->open(intf) < 0) { + lprintf(LOG_DEBUG, "Failed to open LAN interface"); + return NULL; + } + lprintf(LOG_DEBUG, "\topened=[%d], open=[%d]", + intf->opened, intf->open); + } + + for (;;) { + isRetry = ( try > 0 ) ? 1 : 0; + + entry = ipmi_lan_build_cmd(intf, req, isRetry); + if (entry == NULL) { + lprintf(LOG_ERR, "Aborting send command, unable to build"); + return NULL; + } + + if (ipmi_lan_send_packet(intf, entry->msg_data, entry->msg_len) < 0) { + try++; + usleep(5000); + ipmi_req_remove_entry(entry->rq_seq, entry->req.msg.target_cmd); + continue; + } + + /* if we are set to noanswer we do not expect response */ + if (intf->noanswer) + break; + + if (ipmi_oem_active(intf, "intelwv2")) + ipmi_lan_thump(intf); + + usleep(100); + + rsp = ipmi_lan_poll_recv(intf); + + /* Duplicate Request ccode most likely indicates a response to + a previous retry. Ignore and keep polling. */ + if((rsp != NULL) && (rsp->ccode == 0xcf)) { + rsp = NULL; + rsp = ipmi_lan_poll_recv(intf); + } + + if (rsp) + break; + + usleep(5000); + if (++try >= intf->session->retry) { + lprintf(LOG_DEBUG, " No response from remote controller"); + break; + } + } + + // We need to cleanup the existing entries from the list. Because if we + // keep it and then when we send the new command and if the response is for + // old command it still matches it and then returns success. + // This is the corner case where the remote controller responds very slowly. + // + // Example: We have to send command 23 and 2d. + // If we send command,seq as 23,10 and if we dont get any response it will + // retry 4 times with 23,10 and then come out here and indicate that there is no + // reponse from the remote controller and will send the next command for + // ie 2d,11. And if the BMC is slow to respond and returns 23,10 then it + // will match it in the list and will take response of command 23 as response + // for command 2d and return success. So ideally when retries are done and + // are out of this function we should be clearing the list to be safe so that + // we dont match the old response with new request. + // [23, 10] --> BMC + // [23, 10] --> BMC + // [23, 10] --> BMC + // [23, 10] --> BMC + // [2D, 11] --> BMC + // <-- [23, 10] + // here if we maintain 23,10 in the list then it will get matched and consider + // 23 response as response for 2D. + ipmi_req_clear_entries(); + + return rsp; +} + +static uint8_t * +ipmi_lan_build_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp, int * llen) +{ + struct rmcp_hdr rmcp = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_IPMI, + .seq = 0xff, + }; + struct ipmi_session * s = intf->session; + int cs, mp, ap = 0, tmp; + int len; + uint8_t * msg; + + len = rsp->data_len + 22; + if (s->active) + len += 16; + + msg = malloc(len); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + memset(msg, 0, len); + + /* rmcp header */ + memcpy(msg, &rmcp, 4); + len = sizeof(rmcp); + + /* ipmi session header */ + msg[len++] = s->active ? s->authtype : 0; + + if (s->in_seq) { + s->in_seq++; + if (s->in_seq == 0) + s->in_seq++; + } + memcpy(msg+len, &s->in_seq, 4); + len += 4; + memcpy(msg+len, &s->session_id, 4); + len += 4; + + /* session authcode, if session active and authtype is not none */ + if (s->active && s->authtype) { + ap = len; + memcpy(msg+len, s->authcode, 16); + len += 16; + } + + /* message length */ + msg[len++] = rsp->data_len + 8; + + /* message header */ + cs = mp = len; + msg[len++] = IPMI_REMOTE_SWID; + msg[len++] = rsp->msg.netfn << 2; + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs = len; + msg[len++] = IPMI_BMC_SLAVE_ADDR; + msg[len++] = (rsp->msg.seq << 2) | (rsp->msg.lun & 3); + msg[len++] = rsp->msg.cmd; + + /* completion code */ + msg[len++] = rsp->ccode; + + /* message data */ + if (rsp->data_len) { + memcpy(msg+len, rsp->data, rsp->data_len); + len += rsp->data_len; + } + + /* second checksum */ + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + + if (s->active) { + uint8_t * d; + switch (s->authtype) { + case IPMI_SESSION_AUTHTYPE_MD5: + d = ipmi_auth_md5(s, msg+mp, msg[mp-1]); + memcpy(msg+ap, d, 16); + break; + case IPMI_SESSION_AUTHTYPE_MD2: + d = ipmi_auth_md2(s, msg+mp, msg[mp-1]); + memcpy(msg+ap, d, 16); + break; + } + } + + *llen = len; + return msg; +} + +static int +ipmi_lan_send_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp) +{ + uint8_t * msg; + int len = 0; + int rv; + + msg = ipmi_lan_build_rsp(intf, rsp, &len); + if (len <= 0 || msg == NULL) { + lprintf(LOG_ERR, "Invalid response packet"); + if (msg != NULL) { + free(msg); + msg = NULL; + } + return -1; + } + + rv = sendto(intf->fd, msg, len, 0, + (struct sockaddr *)&intf->session->addr, + intf->session->addrlen); + if (rv < 0) { + lprintf(LOG_ERR, "Packet send failed"); + if (msg != NULL) { + free(msg); + msg = NULL; + } + return -1; + } + + if (msg != NULL) { + free(msg); + msg = NULL; + } + return 0; +} + +/* + * IPMI SOL Payload Format + * +--------------------+ + * | rmcp.ver | 4 bytes + * | rmcp.__reserved | + * | rmcp.seq | + * | rmcp.class | + * +--------------------+ + * | session.authtype | 9 bytes + * | session.seq | + * | session.id | + * +--------------------+ + * | message length | 1 byte + * +--------------------+ + * | sol.seq | 5 bytes + * | sol.ack_seq | + * | sol.acc_count | + * | sol.control | + * | sol.__reserved | + * +--------------------+ + * | [request data] | data_len bytes + * +--------------------+ + */ +uint8_t * ipmi_lan_build_sol_msg(struct ipmi_intf * intf, + struct ipmi_v2_payload * payload, + int * llen) +{ + struct rmcp_hdr rmcp = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_IPMI, + .seq = 0xff, + }; + struct ipmi_session * session = intf->session; + + /* msg will hold the entire message to be sent */ + uint8_t * msg; + + int len = 0; + + len = sizeof(rmcp) + // RMCP Header (4) + 10 + // IPMI Session Header + 5 + // SOL header + payload->payload.sol_packet.character_count; // The actual payload + + msg = malloc(len); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + memset(msg, 0, len); + + /* rmcp header */ + memcpy(msg, &rmcp, sizeof(rmcp)); + len = sizeof(rmcp); + + /* ipmi session header */ + msg[len++] = 0; /* SOL is always authtype = NONE */ + msg[len++] = session->in_seq & 0xff; + msg[len++] = (session->in_seq >> 8) & 0xff; + msg[len++] = (session->in_seq >> 16) & 0xff; + msg[len++] = (session->in_seq >> 24) & 0xff; + + msg[len++] = session->session_id & 0xff; + msg[len++] = (session->session_id >> 8) & 0xff; + msg[len++] = (session->session_id >> 16) & 0xff; + msg[len++] = ((session->session_id >> 24) + 0x10) & 0xff; /* Add 0x10 to MSB for SOL */ + + msg[len++] = payload->payload.sol_packet.character_count + 5; + + /* sol header */ + msg[len++] = payload->payload.sol_packet.packet_sequence_number; + msg[len++] = payload->payload.sol_packet.acked_packet_number; + msg[len++] = payload->payload.sol_packet.accepted_character_count; + msg[len] = payload->payload.sol_packet.is_nack ? 0x40 : 0; + msg[len] |= payload->payload.sol_packet.assert_ring_wor ? 0x20 : 0; + msg[len] |= payload->payload.sol_packet.generate_break ? 0x10 : 0; + msg[len] |= payload->payload.sol_packet.deassert_cts ? 0x08 : 0; + msg[len] |= payload->payload.sol_packet.deassert_dcd_dsr ? 0x04 : 0; + msg[len] |= payload->payload.sol_packet.flush_inbound ? 0x02 : 0; + msg[len++] |= payload->payload.sol_packet.flush_outbound ? 0x01 : 0; + + len++; /* On SOL there's and additional fifth byte before the data starts */ + + if (payload->payload.sol_packet.character_count) { + /* We may have data to add */ + memcpy(msg + len, + payload->payload.sol_packet.data, + payload->payload.sol_packet.character_count); + len += payload->payload.sol_packet.character_count; + } + + session->in_seq++; + if (session->in_seq == 0) + session->in_seq++; + + *llen = len; + return msg; +} + +/* + * is_sol_packet + */ +static int +is_sol_packet(struct ipmi_rs * rsp) +{ + return (rsp && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)); +} + + + +/* + * sol_response_acks_packet + */ +static int +sol_response_acks_packet(struct ipmi_rs * rsp, + struct ipmi_v2_payload * payload) +{ + return (is_sol_packet(rsp) && + payload && + (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL) && + (rsp->payload.sol_packet.acked_packet_number == + payload->payload.sol_packet.packet_sequence_number)); +} + +/* + * ipmi_lan_send_sol_payload + * + */ +static struct ipmi_rs * +ipmi_lan_send_sol_payload(struct ipmi_intf * intf, + struct ipmi_v2_payload * payload) +{ + struct ipmi_rs * rsp = NULL; + uint8_t * msg; + int len; + int try = 0; + + if (intf->opened == 0 && intf->open != NULL) { + if (intf->open(intf) < 0) + return NULL; + } + + msg = ipmi_lan_build_sol_msg(intf, payload, &len); + if (len <= 0 || msg == NULL) { + lprintf(LOG_ERR, "Invalid SOL payload packet"); + if (msg != NULL) { + free(msg); + msg = NULL; + } + return NULL; + } + + lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n"); + + for (;;) { + if (ipmi_lan_send_packet(intf, msg, len) < 0) { + try++; + usleep(5000); + continue; + } + + /* if we are set to noanswer we do not expect response */ + if (intf->noanswer) + break; + + if (payload->payload.sol_packet.packet_sequence_number == 0) { + /* We're just sending an ACK. No need to retry. */ + break; + } + + usleep(100); + + rsp = ipmi_lan_recv_sol(intf); /* Grab the next packet */ + + if (sol_response_acks_packet(rsp, payload)) + break; + + else if (is_sol_packet(rsp) && rsp->data_len) + { + /* + * We're still waiting for our ACK, but we more data from + * the BMC + */ + intf->session->sol_data.sol_input_handler(rsp); + } + + usleep(5000); + if (++try >= intf->session->retry) { + lprintf(LOG_DEBUG, " No response from remote controller"); + break; + } + } + + if (msg != NULL) { + free(msg); + msg = NULL; + } + return rsp; +} + +/* + * is_sol_partial_ack + * + * Determine if the response is a partial ACK/NACK that indicates + * we need to resend part of our packet. + * + * returns the number of characters we need to resend, or + * 0 if this isn't an ACK or we don't need to resend anything + */ +static int is_sol_partial_ack(struct ipmi_v2_payload * v2_payload, + struct ipmi_rs * rsp) +{ + int chars_to_resend = 0; + + if (v2_payload && + rsp && + is_sol_packet(rsp) && + sol_response_acks_packet(rsp, v2_payload) && + (rsp->payload.sol_packet.accepted_character_count < + v2_payload->payload.sol_packet.character_count)) + { + if (rsp->payload.sol_packet.accepted_character_count == 0) { + /* We should not resend data */ + chars_to_resend = 0; + } + else + { + chars_to_resend = + v2_payload->payload.sol_packet.character_count - + rsp->payload.sol_packet.accepted_character_count; + } + } + + return chars_to_resend; +} + +/* + * set_sol_packet_sequence_number + */ +static void set_sol_packet_sequence_number(struct ipmi_intf * intf, + struct ipmi_v2_payload * v2_payload) +{ + /* Keep our sequence number sane */ + if (intf->session->sol_data.sequence_number > 0x0F) + intf->session->sol_data.sequence_number = 1; + + v2_payload->payload.sol_packet.packet_sequence_number = + intf->session->sol_data.sequence_number++; +} + +/* + * ipmi_lan_send_sol + * + * Sends a SOL packet.. We handle partial ACK/NACKs from the BMC here. + * + * Returns a pointer to the SOL ACK we received, or + * 0 on failure + * + */ +struct ipmi_rs * +ipmi_lan_send_sol(struct ipmi_intf * intf, + struct ipmi_v2_payload * v2_payload) +{ + struct ipmi_rs * rsp; + int chars_to_resend = 0; + + v2_payload->payload_type = IPMI_PAYLOAD_TYPE_SOL; + + /* + * Payload length is just the length of the character + * data here. + */ + v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */ + + set_sol_packet_sequence_number(intf, v2_payload); + + v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */ + + rsp = ipmi_lan_send_sol_payload(intf, v2_payload); + + /* Determine if we need to resend some of our data */ + chars_to_resend = is_sol_partial_ack(v2_payload, rsp); + + while (chars_to_resend) + { + /* + * We first need to handle any new data we might have + * received in our NACK + */ + if (rsp->data_len) + intf->session->sol_data.sol_input_handler(rsp); + + set_sol_packet_sequence_number(intf, v2_payload); + + /* Just send the required data */ + memmove(v2_payload->payload.sol_packet.data, + v2_payload->payload.sol_packet.data + + rsp->payload.sol_packet.accepted_character_count, + chars_to_resend); + + v2_payload->payload.sol_packet.character_count = chars_to_resend; + + rsp = ipmi_lan_send_sol_payload(intf, v2_payload); + + chars_to_resend = is_sol_partial_ack(v2_payload, rsp); + } + + return rsp; +} + +/* + * check_sol_packet_for_new_data + * + * Determine whether the SOL packet has already been seen + * and whether the packet has new data for us. + * + * This function has the side effect of removing an previously + * seen data, and moving new data to the front. + * + * It also "Remembers" the data so we don't get repeats. + * + */ +static int +check_sol_packet_for_new_data(struct ipmi_intf * intf, + struct ipmi_rs *rsp) +{ + static uint8_t last_received_sequence_number = 0; + static uint8_t last_received_byte_count = 0; + int new_data_size = 0; + + if (rsp && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)) + + { + uint8_t unaltered_data_len = rsp->data_len; + if (rsp->payload.sol_packet.packet_sequence_number == + last_received_sequence_number) + { + /* + * This is the same as the last packet, but may include + * extra data + */ + new_data_size = rsp->data_len - last_received_byte_count; + + if (new_data_size > 0) + { + /* We have more data to process */ + memmove(rsp->data, + rsp->data + + rsp->data_len - new_data_size, + new_data_size); + } + + rsp->data_len = new_data_size; + } + + /* + *Rember the data for next round + */ + if (rsp && rsp->payload.sol_packet.packet_sequence_number) + { + last_received_sequence_number = + rsp->payload.sol_packet.packet_sequence_number; + last_received_byte_count = unaltered_data_len; + } + } + + return new_data_size; +} + +/* + * ack_sol_packet + * + * Provided the specified packet looks reasonable, ACK it. + */ +static void +ack_sol_packet(struct ipmi_intf * intf, + struct ipmi_rs * rsp) +{ + if (rsp && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) && + (rsp->payload.sol_packet.packet_sequence_number)) + { + struct ipmi_v2_payload ack; + + memset(&ack, 0, sizeof(struct ipmi_v2_payload)); + + ack.payload_type = IPMI_PAYLOAD_TYPE_SOL; + + /* + * Payload length is just the length of the character + * data here. + */ + ack.payload_length = 0; + + /* ACK packets have sequence numbers of 0 */ + ack.payload.sol_packet.packet_sequence_number = 0; + + ack.payload.sol_packet.acked_packet_number = + rsp->payload.sol_packet.packet_sequence_number; + + ack.payload.sol_packet.accepted_character_count = rsp->data_len; + + ipmi_lan_send_sol_payload(intf, &ack); + } +} + +/* + * ipmi_recv_sol + * + * Receive a SOL packet and send an ACK in response. + * + */ +static struct ipmi_rs * +ipmi_lan_recv_sol(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf); + + ack_sol_packet(intf, rsp); + + /* + * Remembers the data sent, and alters the data to just + * include the new stuff. + */ + check_sol_packet_for_new_data(intf, rsp); + + return rsp; +} + +/* send a get device id command to keep session active */ +static int +ipmi_lan_keepalive(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req = { msg: { + netfn: IPMI_NETFN_APP, + cmd: 1, + }}; + + if (!intf->opened) + return 0; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) + return -1; + if (rsp->ccode > 0) + return -1; + + return 0; +} + +/* + * IPMI Get Channel Authentication Capabilities Command + */ +static int +ipmi_get_auth_capabilities_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipmi_session * s = intf->session; + uint8_t msg_data[2]; + + msg_data[0] = IPMI_LAN_CHANNEL_E; + msg_data[1] = s->privlvl; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x38; + req.msg.data = msg_data; + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_INFO, "Get Auth Capabilities command failed"); + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "get_auth_capabilities"); + + if (rsp->ccode > 0) { + lprintf(LOG_INFO, "Get Auth Capabilities command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + lprintf(LOG_DEBUG, "Channel %02x Authentication Capabilities:", + rsp->data[0]); + lprintf(LOG_DEBUG, " Privilege Level : %s", + val2str(req.msg.data[1], ipmi_privlvl_vals)); + lprintf(LOG_DEBUG, " Auth Types : %s%s%s%s%s", + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_NONE) ? "NONE " : "", + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD2) ? "MD2 " : "", + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD5) ? "MD5 " : "", + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD) ? "PASSWORD " : "", + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_OEM) ? "OEM " : ""); + lprintf(LOG_DEBUG, " Per-msg auth : %sabled", + (rsp->data[2] & IPMI_AUTHSTATUS_PER_MSG_DISABLED) ? + "dis" : "en"); + lprintf(LOG_DEBUG, " User level auth : %sabled", + (rsp->data[2] & IPMI_AUTHSTATUS_PER_USER_DISABLED) ? + "dis" : "en"); + lprintf(LOG_DEBUG, " Non-null users : %sabled", + (rsp->data[2] & IPMI_AUTHSTATUS_NONNULL_USERS_ENABLED) ? + "en" : "dis"); + lprintf(LOG_DEBUG, " Null users : %sabled", + (rsp->data[2] & IPMI_AUTHSTATUS_NULL_USERS_ENABLED) ? + "en" : "dis"); + lprintf(LOG_DEBUG, " Anonymous login : %sabled", + (rsp->data[2] & IPMI_AUTHSTATUS_ANONYMOUS_USERS_ENABLED) ? + "en" : "dis"); + lprintf(LOG_DEBUG, ""); + + s->authstatus = rsp->data[2]; + + if (s->password && + (s->authtype_set == 0 || + s->authtype_set == IPMI_SESSION_AUTHTYPE_MD5) && + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD5)) + { + s->authtype = IPMI_SESSION_AUTHTYPE_MD5; + } + else if (s->password && + (s->authtype_set == 0 || + s->authtype_set == IPMI_SESSION_AUTHTYPE_MD2) && + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_MD2)) + { + s->authtype = IPMI_SESSION_AUTHTYPE_MD2; + } + else if (s->password && + (s->authtype_set == 0 || + s->authtype_set == IPMI_SESSION_AUTHTYPE_PASSWORD) && + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_PASSWORD)) + { + s->authtype = IPMI_SESSION_AUTHTYPE_PASSWORD; + } + else if (s->password && + (s->authtype_set == 0 || + s->authtype_set == IPMI_SESSION_AUTHTYPE_OEM) && + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_OEM)) + { + s->authtype = IPMI_SESSION_AUTHTYPE_OEM; + } + else if ((s->authtype_set == 0 || + s->authtype_set == IPMI_SESSION_AUTHTYPE_NONE) && + (rsp->data[1] & 1<<IPMI_SESSION_AUTHTYPE_NONE)) + { + s->authtype = IPMI_SESSION_AUTHTYPE_NONE; + } + else { + if (!(rsp->data[1] & 1<<s->authtype_set)) + lprintf(LOG_ERR, "Authentication type %s not supported", + val2str(s->authtype_set, ipmi_authtype_session_vals)); + else + lprintf(LOG_ERR, "No supported authtypes found"); + + return -1; + } + + lprintf(LOG_DEBUG, "Proceeding with AuthType %s", + val2str(s->authtype, ipmi_authtype_session_vals)); + + return 0; +} + +/* + * IPMI Get Session Challenge Command + * returns a temporary session ID and 16 byte challenge string + */ +static int +ipmi_get_session_challenge_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipmi_session * s = intf->session; + uint8_t msg_data[17]; + + memset(msg_data, 0, 17); + msg_data[0] = s->authtype; + memcpy(msg_data+1, s->username, 16); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x39; + req.msg.data = msg_data; + req.msg.data_len = 17; /* 1 byte for authtype, 16 for user */ + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Get Session Challenge command failed"); + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "get_session_challenge"); + + if (rsp->ccode > 0) { + switch (rsp->ccode) { + case 0x81: + lprintf(LOG_ERR, "Invalid user name"); + break; + case 0x82: + lprintf(LOG_ERR, "NULL user name not enabled"); + break; + default: + lprintf(LOG_ERR, "Get Session Challenge command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + } + return -1; + } + + memcpy(&s->session_id, rsp->data, 4); + memcpy(s->challenge, rsp->data + 4, 16); + + lprintf(LOG_DEBUG, "Opening Session"); + lprintf(LOG_DEBUG, " Session ID : %08lx", (long)s->session_id); + lprintf(LOG_DEBUG, " Challenge : %s", buf2str(s->challenge, 16)); + + return 0; +} + +/* + * IPMI Activate Session Command + */ +static int +ipmi_activate_session_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + struct ipmi_session * s = intf->session; + uint8_t msg_data[22]; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x3a; + + msg_data[0] = s->authtype; + msg_data[1] = s->privlvl; + + /* supermicro oem authentication hack */ + if (ipmi_oem_active(intf, "supermicro")) { + uint8_t * special = ipmi_auth_special(s); + memcpy(s->authcode, special, 16); + memset(msg_data + 2, 0, 16); + lprintf(LOG_DEBUG, " OEM Auth : %s", + buf2str(special, 16)); + } else { + memcpy(msg_data + 2, s->challenge, 16); + } + + /* setup initial outbound sequence number */ + get_random(msg_data+18, 4); + + req.msg.data = msg_data; + req.msg.data_len = 22; + + s->active = 1; + + lprintf(LOG_DEBUG, " Privilege Level : %s", + val2str(msg_data[1], ipmi_privlvl_vals)); + lprintf(LOG_DEBUG, " Auth Type : %s", + val2str(s->authtype, ipmi_authtype_session_vals)); + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Activate Session command failed"); + s->active = 0; + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "activate_session"); + + if (rsp->ccode) { + fprintf(stderr, "Activate Session error:"); + switch (rsp->ccode) { + case 0x81: + lprintf(LOG_ERR, "\tNo session slot available"); + break; + case 0x82: + lprintf(LOG_ERR, "\tNo slot available for given user - " + "limit reached"); + break; + case 0x83: + lprintf(LOG_ERR, "\tNo slot available to support user " + "due to maximum privilege capacity"); + break; + case 0x84: + lprintf(LOG_ERR, "\tSession sequence out of range"); + break; + case 0x85: + lprintf(LOG_ERR, "\tInvalid session ID in request"); + break; + case 0x86: + lprintf(LOG_ERR, "\tRequested privilege level " + "exceeds limit"); + break; + case 0xd4: + lprintf(LOG_ERR, "\tInsufficient privilege level"); + break; + default: + lprintf(LOG_ERR, "\t%s", + val2str(rsp->ccode, completion_code_vals)); + } + return -1; + } + + memcpy(&s->session_id, rsp->data + 1, 4); + s->in_seq = rsp->data[8] << 24 | rsp->data[7] << 16 | rsp->data[6] << 8 | rsp->data[5]; + if (s->in_seq == 0) + ++s->in_seq; + + if (s->authstatus & IPMI_AUTHSTATUS_PER_MSG_DISABLED) + s->authtype = IPMI_SESSION_AUTHTYPE_NONE; + else if (s->authtype != (rsp->data[0] & 0xf)) { + lprintf(LOG_ERR, "Invalid Session AuthType %s in response", + val2str(s->authtype, ipmi_authtype_session_vals)); + return -1; + } + + bridge_possible = 1; + + lprintf(LOG_DEBUG, "\nSession Activated"); + lprintf(LOG_DEBUG, " Auth Type : %s", + val2str(rsp->data[0], ipmi_authtype_session_vals)); + lprintf(LOG_DEBUG, " Max Priv Level : %s", + val2str(rsp->data[9], ipmi_privlvl_vals)); + lprintf(LOG_DEBUG, " Session ID : %08lx", (long)s->session_id); + lprintf(LOG_DEBUG, " Inbound Seq : %08lx\n", (long)s->in_seq); + + return 0; +} + + +/* + * IPMI Set Session Privilege Level Command + */ +static int +ipmi_set_session_privlvl_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t privlvl = intf->session->privlvl; + uint8_t backup_bridge_possible = bridge_possible; + + if (privlvl <= IPMI_SESSION_PRIV_USER) + return 0; /* no need to set higher */ + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x3b; + req.msg.data = &privlvl; + req.msg.data_len = 1; + + bridge_possible = 0; + rsp = intf->sendrecv(intf, &req); + bridge_possible = backup_bridge_possible; + + if (rsp == NULL) { + lprintf(LOG_ERR, "Set Session Privilege Level to %s failed", + val2str(privlvl, ipmi_privlvl_vals)); + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "set_session_privlvl"); + + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Session Privilege Level to %s failed: %s", + val2str(privlvl, ipmi_privlvl_vals), + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + lprintf(LOG_DEBUG, "Set Session Privilege Level to %s\n", + val2str(rsp->data[0], ipmi_privlvl_vals)); + + return 0; +} + +static int +ipmi_close_session_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t msg_data[4]; + uint32_t session_id = intf->session->session_id; + + if (intf->session->active == 0) + return -1; + + intf->target_addr = IPMI_BMC_SLAVE_ADDR; + bridge_possible = 0; /* Not a bridge message */ + + memcpy(&msg_data, &session_id, 4); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x3c; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Close Session command failed"); + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "close_session"); + + if (rsp->ccode == 0x87) { + lprintf(LOG_ERR, "Failed to Close Session: invalid " + "session ID %08lx", (long)session_id); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Close Session command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + lprintf(LOG_DEBUG, "Closed Session %08lx\n", (long)session_id); + + return 0; +} + +/* + * IPMI LAN Session Activation (IPMI spec v1.5 section 12.9) + * + * 1. send "RMCP Presence Ping" message, response message will + * indicate whether the platform supports IPMI + * 2. send "Get Channel Authentication Capabilities" command + * with AUTHTYPE = none, response packet will contain information + * about supported challenge/response authentication types + * 3. send "Get Session Challenge" command with AUTHTYPE = none + * and indicate the authentication type in the message, response + * packet will contain challenge string and temporary session ID. + * 4. send "Activate Session" command, authenticated with AUTHTYPE + * sent in previous message. Also sends the initial value for + * the outbound sequence number for BMC. + * 5. BMC returns response confirming session activation and + * session ID for this session and initial inbound sequence. + */ +static int +ipmi_lan_activate_session(struct ipmi_intf * intf) +{ + int rc; + + /* don't fail on ping because its not always supported. + * Supermicro's IPMI LAN 1.5 cards don't tolerate pings. + */ + if (!ipmi_oem_active(intf, "supermicro")) + ipmi_lan_ping(intf); + + /* Some particular Intel boards need special help + */ + if (ipmi_oem_active(intf, "intelwv2")) + ipmi_lan_thump_first(intf); + + rc = ipmi_get_auth_capabilities_cmd(intf); + if (rc < 0) { + goto fail; + } + + rc = ipmi_get_session_challenge_cmd(intf); + if (rc < 0) + goto fail; + + rc = ipmi_activate_session_cmd(intf); + if (rc < 0) + goto fail; + + intf->abort = 0; + + rc = ipmi_set_session_privlvl_cmd(intf); + if (rc < 0) + goto fail; + + return 0; + + fail: + lprintf(LOG_ERR, "Error: Unable to establish LAN session"); + return -1; +} + +static void +ipmi_lan_close(struct ipmi_intf * intf) +{ + if (intf->abort == 0) + ipmi_close_session_cmd(intf); + + if (intf->fd >= 0) + close(intf->fd); + + ipmi_req_clear_entries(); + + if (intf->session != NULL) { + free(intf->session); + intf->session = NULL; + } + + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; + intf = NULL; +} + +static int +ipmi_lan_open(struct ipmi_intf * intf) +{ + int rc; + struct ipmi_session *s; + + if (intf == NULL || intf->session == NULL) + return -1; + s = intf->session; + + if (s->port == 0) + s->port = IPMI_LAN_PORT; + if (s->privlvl == 0) + s->privlvl = IPMI_SESSION_PRIV_ADMIN; + if (s->timeout == 0) + s->timeout = IPMI_LAN_TIMEOUT; + if (s->retry == 0) + s->retry = IPMI_LAN_RETRY; + + if (s->hostname == NULL || strlen((const char *)s->hostname) == 0) { + lprintf(LOG_ERR, "No hostname specified!"); + return -1; + } + + intf->abort = 1; + + intf->session->sol_data.sequence_number = 1; + + if (ipmi_intf_socket_connect (intf) == -1) { + lprintf(LOG_ERR, "Could not open socket!"); + return -1; + } + + if (intf->fd < 0) { + lperror(LOG_ERR, "Connect to %s failed", + s->hostname); + intf->close(intf); + return -1; + } + + intf->opened = 1; + + /* try to open session */ + rc = ipmi_lan_activate_session(intf); + if (rc < 0) { + intf->close(intf); + intf->opened = 0; + return -1; + } + + intf->manufacturer_id = ipmi_get_oem(intf); + + /* automatically detect interface request and response sizes */ + hpm2_detect_max_payload_size(intf); + + return intf->fd; +} + +static int +ipmi_lan_setup(struct ipmi_intf * intf) +{ + intf->session = malloc(sizeof(struct ipmi_session)); + if (intf->session == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + memset(intf->session, 0, sizeof(struct ipmi_session)); + + /* setup default LAN maximum request and response sizes */ + intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE; + intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE; + + return 0; +} + +static void +ipmi_lan_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size) +{ + if (size + 7 > 0xFF) { + size = 0xFF - 7; + } + + intf->max_request_data_size = size; +} + +static void +ipmi_lan_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size) +{ + if (size + 8 > 0xFF) { + size = 0xFF - 8; + } + + intf->max_response_data_size = size; +} diff --git a/src/plugins/lan/lan.h b/src/plugins/lan/lan.h new file mode 100644 index 0000000..3ba3055 --- /dev/null +++ b/src/plugins/lan/lan.h @@ -0,0 +1,41 @@ +/* + * 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_LAN_H +#define IPMI_LAN_H + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> + +extern struct ipmi_intf ipmi_lan_intf; + +#endif /*IPMI_LAN_H*/ diff --git a/src/plugins/lan/md5.c b/src/plugins/lan/md5.c new file mode 100644 index 0000000..572c7c8 --- /dev/null +++ b/src/plugins/lan/md5.c @@ -0,0 +1,381 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.1 2003/11/18 17:56:02 iceblink Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include <string.h> + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include <stdio.h> in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include <string.h> + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/src/plugins/lan/md5.h b/src/plugins/lan/md5.h new file mode 100644 index 0000000..11fd117 --- /dev/null +++ b/src/plugins/lan/md5.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.1 2003/11/18 17:56:02 iceblink Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke <purschke@bnl.gov>. + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/src/plugins/lan/rmcp.h b/src/plugins/lan/rmcp.h new file mode 100644 index 0000000..b979d92 --- /dev/null +++ b/src/plugins/lan/rmcp.h @@ -0,0 +1,99 @@ +/* + * 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_RMCP_H +#define IPMI_RMCP_H + +#include <ipmitool/helper.h> +#include "lan.h" +#include "asf.h" + +#define RMCP_VERSION_1 0x06 + +#define RMCP_UDP_PORT 0x26f /* port 623 */ +#define RMCP_UDP_SECURE_PORT 0x298 /* port 664 */ + +#define RMCP_TYPE_MASK 0x80 +#define RMCP_TYPE_NORM 0x00 +#define RMCP_TYPE_ACK 0x01 + +static const struct valstr rmcp_type_vals[] __attribute__((unused)) = { + { RMCP_TYPE_NORM, "Normal RMCP" }, + { RMCP_TYPE_ACK, "RMCP ACK" }, + { 0, NULL } +}; + +#define RMCP_CLASS_MASK 0x1f +#define RMCP_CLASS_ASF 0x06 +#define RMCP_CLASS_IPMI 0x07 +#define RMCP_CLASS_OEM 0x08 + +static const struct valstr rmcp_class_vals[] __attribute__((unused)) = { + { RMCP_CLASS_ASF, "ASF" }, + { RMCP_CLASS_IPMI, "IPMI" }, + { RMCP_CLASS_OEM, "OEM" }, + { 0, NULL } +}; + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +/* RMCP message header */ +struct rmcp_hdr { + uint8_t ver; + uint8_t __reserved; + uint8_t seq; + uint8_t class; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct rmcp_pong { + struct rmcp_hdr rmcp; + struct asf_hdr asf; + uint32_t iana; + uint32_t oem; + uint8_t sup_entities; + uint8_t sup_interact; + uint8_t reserved[6]; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +int handle_rmcp(struct ipmi_intf * intf, uint8_t * data, int data_len); + +#endif /* IPMI_RMCP_H */ diff --git a/src/plugins/lanplus/Makefile.am b/src/plugins/lanplus/Makefile.am new file mode 100644 index 0000000..428eb04 --- /dev/null +++ b/src/plugins/lanplus/Makefile.am @@ -0,0 +1,45 @@ +# 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_lanplus.la +noinst_LTLIBRARIES = @INTF_LANPLUS_LIB@ +libintf_lanplus_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_lanplus_la_SOURCES = \ + rmcp.h asf.h \ + lanplus.c lanplus.h \ + lanplus_strings.c \ + lanplus_crypt.c lanplus_crypt.h \ + lanplus_dump.h lanplus_dump.c \ + lanplus_crypt_impl.h lanplus_crypt_impl.c + diff --git a/src/plugins/lanplus/Makefile.in b/src/plugins/lanplus/Makefile.in new file mode 100644 index 0000000..6860f1b --- /dev/null +++ b/src/plugins/lanplus/Makefile.in @@ -0,0 +1,550 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/lanplus +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_lanplus_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_lanplus_la_OBJECTS = lanplus.lo lanplus_strings.lo \ + lanplus_crypt.lo lanplus_dump.lo lanplus_crypt_impl.lo +libintf_lanplus_la_OBJECTS = $(am_libintf_lanplus_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_lanplus_la_SOURCES) +DIST_SOURCES = $(libintf_lanplus_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_lanplus.la +noinst_LTLIBRARIES = @INTF_LANPLUS_LIB@ +libintf_lanplus_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_lanplus_la_SOURCES = \ + rmcp.h asf.h \ + lanplus.c lanplus.h \ + lanplus_strings.c \ + lanplus_crypt.c lanplus_crypt.h \ + lanplus_dump.h lanplus_dump.c \ + lanplus_crypt_impl.h lanplus_crypt_impl.c + +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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/lanplus/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/lanplus/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_lanplus.la: $(libintf_lanplus_la_OBJECTS) $(libintf_lanplus_la_DEPENDENCIES) $(EXTRA_libintf_lanplus_la_DEPENDENCIES) + $(LINK) $(libintf_lanplus_la_OBJECTS) $(libintf_lanplus_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lanplus.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lanplus_crypt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lanplus_crypt_impl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lanplus_dump.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lanplus_strings.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/lanplus/asf.h b/src/plugins/lanplus/asf.h new file mode 100644 index 0000000..7a30418 --- /dev/null +++ b/src/plugins/lanplus/asf.h @@ -0,0 +1,75 @@ +/* + * 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_ASF_H +#define IPMI_ASF_H + +#include <ipmitool/helper.h> +#include "lanplus.h" + +#define ASF_RMCP_IANA 0x000011be + +#define ASF_TYPE_PING 0x80 +#define ASF_TYPE_PONG 0x40 + +static const struct valstr asf_type_vals[] __attribute__((unused)) = { + { 0x10, "Reset" }, + { 0x11, "Power-up" }, + { 0x12, "Unconditional Power-down" }, + { 0x13, "Power Cycle" }, + { 0x40, "Presence Pong" }, + { 0x41, "Capabilities Response" }, + { 0x42, "System State Response" }, + { 0x80, "Presence Ping" }, + { 0x81, "Capabilities Request" }, + { 0x82, "System State Request" }, + { 0x00, NULL } +}; + +/* ASF message header */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct asf_hdr { + uint32_t iana; + uint8_t type; + uint8_t tag; + uint8_t __reserved; + uint8_t len; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +int handle_asf(struct ipmi_intf * intf, uint8_t * data, int data_len); + +#endif /* IPMI_ASF_H */ diff --git a/src/plugins/lanplus/lanplus.c b/src/plugins/lanplus/lanplus.c new file mode 100644 index 0000000..27b9610 --- /dev/null +++ b/src/plugins/lanplus/lanplus.c @@ -0,0 +1,3680 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <inttypes.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <unistd.h> +#include <netdb.h> +#include <time.h> +#include <fcntl.h> +#include <assert.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <ipmitool/helper.h> +#include <ipmitool/log.h> +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_lanp.h> +#include <ipmitool/ipmi_channel.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/ipmi_strings.h> +#include <ipmitool/hpm2.h> +#include <ipmitool/bswap.h> +#include <openssl/rand.h> + +#include "lanplus.h" +#include "lanplus_crypt.h" +#include "lanplus_crypt_impl.h" +#include "lanplus_dump.h" +#include "rmcp.h" +#include "asf.h" + +/* + * LAN interface is required to support 45 byte request transactions and + * 42 byte response transactions. + */ +#define IPMI_LAN_MAX_REQUEST_SIZE 38 /* 45 - 7 */ +#define IPMI_LAN_MAX_RESPONSE_SIZE 34 /* 42 - 8 */ + +extern const struct valstr ipmi_rakp_return_codes[]; +extern const struct valstr ipmi_priv_levels[]; +extern const struct valstr ipmi_auth_algorithms[]; +extern const struct valstr ipmi_integrity_algorithms[]; +extern const struct valstr ipmi_encryption_algorithms[]; + +static struct ipmi_rq_entry * ipmi_req_entries; +static struct ipmi_rq_entry * ipmi_req_entries_tail; + + +static int ipmi_lanplus_setup(struct ipmi_intf * intf); +static int ipmi_lanplus_keepalive(struct ipmi_intf * intf); +static int ipmi_lan_send_packet(struct ipmi_intf * intf, uint8_t * data, int data_len); +static struct ipmi_rs * ipmi_lan_recv_packet(struct ipmi_intf * intf); +static struct ipmi_rs * ipmi_lan_poll_recv(struct ipmi_intf * intf); +static struct ipmi_rs * ipmi_lanplus_send_ipmi_cmd(struct ipmi_intf * intf, struct ipmi_rq * req); +static struct ipmi_rs * ipmi_lanplus_send_payload(struct ipmi_intf * intf, + struct ipmi_v2_payload * payload); +static void getIpmiPayloadWireRep( + struct ipmi_intf * intf, + struct ipmi_v2_payload * payload, /* in */ + uint8_t * out, + struct ipmi_rq * req, + uint8_t rq_seq, + uint8_t curr_seq); +static void getSolPayloadWireRep( + struct ipmi_intf * intf, + uint8_t * msg, + struct ipmi_v2_payload * payload); +static void read_open_session_response(struct ipmi_rs * rsp, int offset); +static void read_rakp2_message(struct ipmi_rs * rsp, int offset, uint8_t alg); +static void read_rakp4_message(struct ipmi_rs * rsp, int offset, uint8_t alg); +static void read_session_data(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s); +static void read_session_data_v15(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s); +static void read_session_data_v2x(struct ipmi_rs * rsp, int * offset, struct ipmi_session *s); +static void read_ipmi_response(struct ipmi_rs * rsp, int * offset); +static void read_sol_packet(struct ipmi_rs * rsp, int * offset); +static struct ipmi_rs * ipmi_lanplus_recv_sol(struct ipmi_intf * intf); +static struct ipmi_rs * ipmi_lanplus_send_sol( + struct ipmi_intf * intf, + struct ipmi_v2_payload * payload); +static int check_sol_packet_for_new_data( + struct ipmi_intf * intf, + struct ipmi_rs *rsp); +static void ack_sol_packet( + struct ipmi_intf * intf, + struct ipmi_rs * rsp); +static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size); +static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size); + +static uint8_t bridgePossible = 0; + +struct ipmi_intf ipmi_lanplus_intf = { + name: "lanplus", + desc: "IPMI v2.0 RMCP+ LAN Interface", + setup: ipmi_lanplus_setup, + open: ipmi_lanplus_open, + close: ipmi_lanplus_close, + sendrecv: ipmi_lanplus_send_ipmi_cmd, + recv_sol: ipmi_lanplus_recv_sol, + send_sol: ipmi_lanplus_send_sol, + keepalive: ipmi_lanplus_keepalive, + set_max_request_data_size: ipmi_lanp_set_max_rq_data_size, + set_max_response_data_size: ipmi_lanp_set_max_rp_data_size, + target_addr: IPMI_BMC_SLAVE_ADDR, +}; + + +extern int verbose; + + + +/* + * lanplus_get_requested_ciphers + * + * Set the authentication, integrity and encryption algorithms based + * on the cipher suite ID. See table 22-19 in the IPMIv2 spec for the + * source of this information. + * + * param cipher_suite_id [in] + * param auth_alg [out] + * param integrity_alg [out] + * param crypt_alg [out] + * + * returns 0 on success + * 1 on failure + */ +int lanplus_get_requested_ciphers(int cipher_suite_id, + uint8_t * auth_alg, + uint8_t * integrity_alg, + uint8_t * crypt_alg) +{ + if ((cipher_suite_id < 0) || (cipher_suite_id > 14)) + return 1; + + /* See table 22-19 for the source of the statement */ + switch (cipher_suite_id) + { + case 0: + *auth_alg = IPMI_AUTH_RAKP_NONE; + *integrity_alg = IPMI_INTEGRITY_NONE; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 1: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA1; + *integrity_alg = IPMI_INTEGRITY_NONE; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 2: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA1; + *integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 3: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA1; + *integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96; + *crypt_alg = IPMI_CRYPT_AES_CBC_128; + break; + case 4: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA1; + *integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96; + *crypt_alg = IPMI_CRYPT_XRC4_128; + break; + case 5: + *auth_alg = IPMI_AUTH_RAKP_HMAC_SHA1; + *integrity_alg = IPMI_INTEGRITY_HMAC_SHA1_96; + *crypt_alg = IPMI_CRYPT_XRC4_40; + break; + case 6: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_NONE; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 7: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 8: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128; + *crypt_alg = IPMI_CRYPT_AES_CBC_128; + break; + case 9: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128; + *crypt_alg = IPMI_CRYPT_XRC4_128; + break; + case 10: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_HMAC_MD5_128; + *crypt_alg = IPMI_CRYPT_XRC4_40; + break; + case 11: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_MD5_128; + *crypt_alg = IPMI_CRYPT_NONE; + break; + case 12: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_MD5_128; + *crypt_alg = IPMI_CRYPT_AES_CBC_128; + break; + case 13: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_MD5_128; + *crypt_alg = IPMI_CRYPT_XRC4_128; + break; + case 14: + *auth_alg = IPMI_AUTH_RAKP_HMAC_MD5; + *integrity_alg = IPMI_INTEGRITY_MD5_128; + *crypt_alg = IPMI_CRYPT_XRC4_40; + break; + } + + return 0; +} + + + +/* + * Reverse the order of arbitrarily long strings of bytes + */ +void lanplus_swap( + uint8_t * buffer, + int length) +{ + int i; + uint8_t temp; + + for (i =0; i < length/2; ++i) + { + temp = buffer[i]; + buffer[i] = buffer[length - 1 - i]; + buffer[length - 1 - i] = temp; + } +} + + + +static const struct valstr plus_payload_types_vals[] = { + { IPMI_PAYLOAD_TYPE_IPMI, "IPMI (0)" }, // IPMI Message + { IPMI_PAYLOAD_TYPE_SOL, "SOL (1)" }, // SOL (Serial over LAN) + { IPMI_PAYLOAD_TYPE_OEM, "OEM (2)" }, // OEM Explicid + + { IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST, "OpenSession Req (0x10)" }, + { IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE,"OpenSession Resp (0x11)" }, + { IPMI_PAYLOAD_TYPE_RAKP_1, "RAKP1 (0x12)" }, + { IPMI_PAYLOAD_TYPE_RAKP_2, "RAKP2 (0x13)" }, + { IPMI_PAYLOAD_TYPE_RAKP_3, "RAKP3 (0x14)" }, + { IPMI_PAYLOAD_TYPE_RAKP_4, "RAKP4 (0x15)" }, + { 0x00, NULL }, +}; + + +static struct ipmi_rq_entry * +ipmi_req_add_entry(struct ipmi_intf * intf, struct ipmi_rq * req, uint8_t req_seq) +{ + struct ipmi_rq_entry * e; + + e = malloc(sizeof(struct ipmi_rq_entry)); + if (e == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + + memset(e, 0, sizeof(struct ipmi_rq_entry)); + memcpy(&e->req, req, sizeof(struct ipmi_rq)); + + e->intf = intf; + e->rq_seq = req_seq; + + if (ipmi_req_entries == NULL) + ipmi_req_entries = e; + else + ipmi_req_entries_tail->next = e; + + ipmi_req_entries_tail = e; + lprintf(LOG_DEBUG+3, "added list entry seq=0x%02x cmd=0x%02x", + e->rq_seq, e->req.msg.cmd); + return e; +} + + +static struct ipmi_rq_entry * +ipmi_req_lookup_entry(uint8_t seq, uint8_t cmd) +{ + struct ipmi_rq_entry * e = ipmi_req_entries; + + while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) { + if (e == e->next) + return NULL; + e = e->next; + } + return e; +} + +static void +ipmi_req_remove_entry(uint8_t seq, uint8_t cmd) +{ + struct ipmi_rq_entry * p, * e, * saved_next_entry; + + e = p = ipmi_req_entries; + + while (e && (e->rq_seq != seq || e->req.msg.cmd != cmd)) { + p = e; + e = e->next; + } + if (e) { + lprintf(LOG_DEBUG+3, "removed list entry seq=0x%02x cmd=0x%02x", + seq, cmd); + saved_next_entry = e->next; + p->next = (p->next == e->next) ? NULL : e->next; + /* If entry being removed is first in list, fix up list head */ + if (ipmi_req_entries == e) { + if (ipmi_req_entries != p) + ipmi_req_entries = p; + else + ipmi_req_entries = saved_next_entry; + } + /* If entry being removed is last in list, fix up list tail */ + if (ipmi_req_entries_tail == e) { + if (ipmi_req_entries_tail != p) + ipmi_req_entries_tail = p; + else + ipmi_req_entries_tail = NULL; + } + + if (e->msg_data) { + free(e->msg_data); + e->msg_data = NULL; + } + free(e); + e = NULL; + } +} + +static void +ipmi_req_clear_entries(void) +{ + struct ipmi_rq_entry * p, * e; + + e = ipmi_req_entries; + while (e) { + lprintf(LOG_DEBUG+3, "cleared list entry seq=0x%02x cmd=0x%02x", + e->rq_seq, e->req.msg.cmd); + p = e->next; + free(e); + e = p; + } +} + + +int +ipmi_lan_send_packet( + struct ipmi_intf * intf, + uint8_t * data, int + data_len) +{ + if (verbose >= 5) + printbuf(data, data_len, ">> sending packet"); + + return send(intf->fd, data, data_len, 0); +} + + + +struct ipmi_rs * +ipmi_lan_recv_packet(struct ipmi_intf * intf) +{ + static struct ipmi_rs rsp; + fd_set read_set, err_set; + struct timeval tmout; + int ret; + + FD_ZERO(&read_set); + FD_SET(intf->fd, &read_set); + + FD_ZERO(&err_set); + FD_SET(intf->fd, &err_set); + + tmout.tv_sec = intf->session->timeout; + tmout.tv_usec = 0; + + ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout); + if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) + return NULL; + + /* the first read may return ECONNREFUSED because the rmcp ping + * packet--sent to UDP port 623--will be processed by both the + * BMC and the OS. + * + * The problem with this is that the ECONNREFUSED takes + * priority over any other received datagram; that means that + * the Connection Refused shows up _before_ the response packet, + * regardless of the order they were sent out. (unless the + * response is read before the connection refused is returned) + */ + ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); + + if (ret < 0) { + FD_ZERO(&read_set); + FD_SET(intf->fd, &read_set); + + FD_ZERO(&err_set); + FD_SET(intf->fd, &err_set); + + tmout.tv_sec = intf->session->timeout; + tmout.tv_usec = 0; + + ret = select(intf->fd + 1, &read_set, NULL, &err_set, &tmout); + if (ret < 0 || FD_ISSET(intf->fd, &err_set) || !FD_ISSET(intf->fd, &read_set)) + return NULL; + + ret = recv(intf->fd, &rsp.data, IPMI_BUF_SIZE, 0); + if (ret < 0) + return NULL; + } + + if (ret == 0) + return NULL; + + rsp.data[ret] = '\0'; + rsp.data_len = ret; + + if (verbose >= 5) + printbuf(rsp.data, rsp.data_len, "<< received packet"); + + return &rsp; +} + + + +/* + * parse response RMCP "pong" packet + * + * return -1 if ping response not received + * returns 0 if IPMI is NOT supported + * returns 1 if IPMI is supported + * + * udp.source = 0x026f // RMCP_UDP_PORT + * udp.dest = ? // udp.source from rmcp-ping + * udp.len = ? + * udp.check = ? + * rmcp.ver = 0x06 // RMCP Version 1.0 + * rmcp.__res = 0x00 // RESERVED + * rmcp.seq = 0xff // no RMCP ACK + * rmcp.class = 0x06 // RMCP_CLASS_ASF + * asf.iana = 0x000011be // ASF_RMCP_IANA + * asf.type = 0x40 // ASF_TYPE_PONG + * asf.tag = ? // asf.tag from rmcp-ping + * asf.__res = 0x00 // RESERVED + * asf.len = 0x10 // 16 bytes + * asf.data[3:0]= 0x000011be // IANA# = RMCP_ASF_IANA if no OEM + * asf.data[7:4]= 0x00000000 // OEM-defined (not for IPMI) + * asf.data[8] = 0x81 // supported entities + * // [7]=IPMI [6:4]=RES [3:0]=ASF_1.0 + * asf.data[9] = 0x00 // supported interactions (reserved) + * asf.data[f:a]= 0x000000000000 + */ +static int +ipmi_handle_pong(struct ipmi_intf * intf, struct ipmi_rs * rsp) +{ + struct rmcp_pong { + struct rmcp_hdr rmcp; + struct asf_hdr asf; + uint32_t iana; + uint32_t oem; + uint8_t sup_entities; + uint8_t sup_interact; + uint8_t reserved[6]; + } * pong; + + if (!rsp) + return -1; + + pong = (struct rmcp_pong *)rsp->data; + + if (verbose) + printf("Received IPMI/RMCP response packet: " + "IPMI%s Supported\n", + (pong->sup_entities & 0x80) ? "" : " NOT"); + + if (verbose > 1) + printf(" ASF Version %s\n" + " RMCP Version %s\n" + " RMCP Sequence %d\n" + " IANA Enterprise %lu\n\n", + (pong->sup_entities & 0x01) ? "1.0" : "unknown", + (pong->rmcp.ver == 6) ? "1.0" : "unknown", + pong->rmcp.seq, + (unsigned long)ntohl(pong->iana)); + + return (pong->sup_entities & 0x80) ? 1 : 0; +} + + +/* build and send RMCP presence ping packet + * + * RMCP ping + * + * udp.source = ? + * udp.dest = 0x026f // RMCP_UDP_PORT + * udp.len = ? + * udp.check = ? + * rmcp.ver = 0x06 // RMCP Version 1.0 + * rmcp.__res = 0x00 // RESERVED + * rmcp.seq = 0xff // no RMCP ACK + * rmcp.class = 0x06 // RMCP_CLASS_ASF + * asf.iana = 0x000011be // ASF_RMCP_IANA + * asf.type = 0x80 // ASF_TYPE_PING + * asf.tag = ? // ASF sequence number + * asf.__res = 0x00 // RESERVED + * asf.len = 0x00 + * + */ +int +ipmiv2_lan_ping(struct ipmi_intf * intf) +{ + struct asf_hdr asf_ping = { + .iana = htonl(ASF_RMCP_IANA), + .type = ASF_TYPE_PING, + }; + struct rmcp_hdr rmcp_ping = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_ASF, + .seq = 0xff, + }; + uint8_t * data; + int len = sizeof(rmcp_ping) + sizeof(asf_ping); + int rv; + + data = malloc(len); + if (data == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + memset(data, 0, len); + memcpy(data, &rmcp_ping, sizeof(rmcp_ping)); + memcpy(data+sizeof(rmcp_ping), &asf_ping, sizeof(asf_ping)); + + lprintf(LOG_DEBUG, "Sending IPMI/RMCP presence ping packet"); + + rv = ipmi_lan_send_packet(intf, data, len); + + free(data); + data = NULL; + + if (rv < 0) { + lprintf(LOG_ERR, "Unable to send IPMI presence ping packet"); + return -1; + } + + if (ipmi_lan_poll_recv(intf) == 0) + return 0; + + return 1; +} + + +/** + * + * ipmi_lan_poll_recv + * + * Receive whatever comes back. Ignore received packets that don't correspond + * to a request we've sent. + * + * Returns: the ipmi_rs packet describing the/a reponse we expect. + */ +static struct ipmi_rs * +ipmi_lan_poll_recv(struct ipmi_intf * intf) +{ + struct rmcp_hdr rmcp_rsp; + struct ipmi_rs * rsp; + struct ipmi_session * session = intf->session; + int offset, rv; + uint16_t payload_size; + uint8_t ourAddress = intf->my_addr; + + if (ourAddress == 0) { + ourAddress = IPMI_BMC_SLAVE_ADDR; + } + + rsp = ipmi_lan_recv_packet(intf); + + /* + * Not positive why we're looping. Do we sometimes get stuff we don't + * expect? + */ + while (rsp != NULL) { + + /* parse response headers */ + memcpy(&rmcp_rsp, rsp->data, 4); + + if (rmcp_rsp.class == RMCP_CLASS_ASF) { + /* might be ping response packet */ + rv = ipmi_handle_pong(intf, rsp); + return (rv <= 0) ? NULL : rsp; + } + + if (rmcp_rsp.class != RMCP_CLASS_IPMI) { + lprintf(LOG_DEBUG, "Invalid RMCP class: %x", + rmcp_rsp.class); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + + /* + * The authtype / payload type determines what we are receiving + */ + offset = 4; + + + /*-------------------------------------------------------------------- + * + * The current packet could be one of several things: + * + * 1) An IPMI 1.5 packet (the response to our GET CHANNEL + * AUTHENTICATION CAPABILITIES request) + * 2) An RMCP+ message with an IPMI reponse payload + * 3) AN RMCP+ open session response + * 4) An RAKP-2 message (response to an RAKP 1 message) + * 5) An RAKP-4 message (response to an RAKP 3 message) + * 6) A Serial Over LAN packet + * 7) An Invalid packet (one that doesn't match a request) + * ------------------------------------------------------------------- + */ + + read_session_data(rsp, &offset, intf->session); + + if (lanplus_has_valid_auth_code(rsp, intf->session) == 0) + { + lprintf(LOG_ERR, "ERROR: Received message with invalid authcode!"); + rsp = ipmi_lan_recv_packet(intf); + assert(0); + //continue; + } + + if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE) && + (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && + (rsp->session.bEncrypted)) + + { + lanplus_decrypt_payload(session->v2_data.crypt_alg, + session->v2_data.k2, + rsp->data + offset, + rsp->session.msglen, + rsp->data + offset, + &payload_size); + } + else + payload_size = rsp->session.msglen; + + + /* + * Handle IPMI responses (case #1 and #2) -- all IPMI reponses + */ + if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI) + { + struct ipmi_rq_entry * entry; + int payload_start = offset; + int extra_data_length; + read_ipmi_response(rsp, &offset); + + lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header"); + lprintf(LOG_DEBUG+1, "<< Authtype : %s", + val2str(rsp->session.authtype, ipmi_authtype_session_vals)); + lprintf(LOG_DEBUG+1, "<< Payload type : %s", + val2str(rsp->session.payloadtype, plus_payload_types_vals)); + lprintf(LOG_DEBUG+1, "<< Session ID : 0x%08lx", + (long)rsp->session.id); + lprintf(LOG_DEBUG+1, "<< Sequence : 0x%08lx", + (long)rsp->session.seq); + lprintf(LOG_DEBUG+1, "<< IPMI Msg/Payload Length : %d", + rsp->session.msglen); + lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header"); + lprintf(LOG_DEBUG+1, "<< Rq Addr : %02x", + rsp->payload.ipmi_response.rq_addr); + lprintf(LOG_DEBUG+1, "<< NetFn : %02x", + rsp->payload.ipmi_response.netfn); + lprintf(LOG_DEBUG+1, "<< Rq LUN : %01x", + rsp->payload.ipmi_response.rq_lun); + lprintf(LOG_DEBUG+1, "<< Rs Addr : %02x", + rsp->payload.ipmi_response.rs_addr); + lprintf(LOG_DEBUG+1, "<< Rq Seq : %02x", + rsp->payload.ipmi_response.rq_seq); + lprintf(LOG_DEBUG+1, "<< Rs Lun : %01x", + rsp->payload.ipmi_response.rs_lun); + lprintf(LOG_DEBUG+1, "<< Command : %02x", + rsp->payload.ipmi_response.cmd); + lprintf(LOG_DEBUG+1, "<< Compl Code : 0x%02x", + rsp->ccode); + + /* Are we expecting this packet? */ + entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq, + rsp->payload.ipmi_response.cmd); + + if (entry != NULL) { + lprintf(LOG_DEBUG+2, "IPMI Request Match found"); + if ( intf->target_addr != intf->my_addr && + bridgePossible && + rsp->data_len && + rsp->payload.ipmi_response.cmd == 0x34 && + (rsp->payload.ipmi_response.netfn == 0x06 || + rsp->payload.ipmi_response.netfn == 0x07) && + rsp->payload.ipmi_response.rs_lun == 0 ) + { + /* Check completion code */ + if (rsp->data[offset-1] == 0) + { + lprintf(LOG_DEBUG, "Bridged command answer," + " waiting for next answer... "); + ipmi_req_remove_entry( + rsp->payload.ipmi_response.rq_seq, + rsp->payload.ipmi_response.cmd); + return ipmi_lan_poll_recv(intf); + } + else + { + lprintf(LOG_DEBUG, "WARNING: Bridged " + "cmd ccode = 0x%02x", + rsp->data[offset-1]); + } + + if (rsp->data_len && + rsp->payload.ipmi_response.cmd == 0x34) { + memcpy(rsp->data, &rsp->data[offset], + (rsp->data_len-offset)); + if (verbose > 2) + printbuf( &rsp->data[offset], + (rsp->data_len-offset), + "bridge command response"); + } + } + + ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq, + rsp->payload.ipmi_response.cmd); + } else { + lprintf(LOG_INFO, "IPMI Request Match NOT FOUND"); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + /* + * Good packet. Shift response data to start of array. + * rsp->data becomes the variable length IPMI response data + * rsp->data_len becomes the length of that data + */ + extra_data_length = payload_size - (offset - payload_start) - 1; + if (rsp != NULL && extra_data_length) + { + rsp->data_len = extra_data_length; + memmove(rsp->data, rsp->data + offset, extra_data_length); + } + else + rsp->data_len = 0; + + break; + } + + + /* + * Open Response + */ + else if (rsp->session.payloadtype == + IPMI_PAYLOAD_TYPE_RMCP_OPEN_RESPONSE) + { + if (session->v2_data.session_state != + LANPLUS_STATE_OPEN_SESSION_SENT) + { + lprintf(LOG_ERR, "Error: Received an Unexpected Open Session " + "Response"); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + read_open_session_response(rsp, offset); + break; + } + + + /* + * RAKP 2 + */ + else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_2) + { + if (session->v2_data.session_state != LANPLUS_STATE_RAKP_1_SENT) + { + lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 2 message"); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + read_rakp2_message(rsp, offset, session->v2_data.auth_alg); + break; + } + + + /* + * RAKP 4 + */ + else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_RAKP_4) + { + if (session->v2_data.session_state != LANPLUS_STATE_RAKP_3_SENT) + { + lprintf(LOG_ERR, "Error: Received an Unexpected RAKP 4 message"); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + read_rakp4_message(rsp, offset, session->v2_data.auth_alg); + break; + } + + + /* + * SOL + */ + else if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) + { + int payload_start = offset; + int extra_data_length; + + if (session->v2_data.session_state != LANPLUS_STATE_ACTIVE) + { + lprintf(LOG_ERR, "Error: Received an Unexpected SOL packet"); + rsp = ipmi_lan_recv_packet(intf); + continue; + } + + read_sol_packet(rsp, &offset); + extra_data_length = payload_size - (offset - payload_start); + if (rsp && extra_data_length) + { + rsp->data_len = extra_data_length; + memmove(rsp->data, rsp->data + offset, extra_data_length); + } + else + rsp->data_len = 0; + + break; + } + + else + { + lprintf(LOG_ERR, "Invalid RMCP+ payload type : 0x%x", + rsp->session.payloadtype); + assert(0); + } + } + + return rsp; +} + + + +/* + * read_open_session_reponse + * + * Initialize the ipmi_rs from the IPMI 2.x open session response data. + * + * The offset should point to the first byte of the the Open Session Response + * payload when this function is called. + * + * param rsp [in/out] reading from the data and writing to the open_session_response + * section + * param offset [in] tells us where the Open Session Response payload starts + * + * returns 0 on success, 1 on error + */ +void +read_open_session_response(struct ipmi_rs * rsp, int offset) +{ + memset(&rsp->payload.open_session_response, 0, + sizeof(rsp->payload.open_session_response)); + + /* Message tag */ + rsp->payload.open_session_response.message_tag = rsp->data[offset]; + + /* RAKP reponse code */ + rsp->payload.open_session_response.rakp_return_code = rsp->data[offset + 1]; + + /* Maximum privilege level */ + rsp->payload.open_session_response.max_priv_level = rsp->data[offset + 2]; + + /*** offset + 3 is reserved ***/ + + /* Remote console session ID */ + memcpy(&(rsp->payload.open_session_response.console_id), + rsp->data + offset + 4, + 4); + #if WORDS_BIGENDIAN + rsp->payload.open_session_response.console_id = + BSWAP_32(rsp->payload.open_session_response.console_id); + #endif + + /* only tag, status, privlvl, and console id are returned if error */ + if (rsp->payload.open_session_response.rakp_return_code != + IPMI_RAKP_STATUS_NO_ERRORS) + return; + + /* BMC session ID */ + memcpy(&(rsp->payload.open_session_response.bmc_id), + rsp->data + offset + 8, + 4); + #if WORDS_BIGENDIAN + rsp->payload.open_session_response.bmc_id = + BSWAP_32(rsp->payload.open_session_response.bmc_id); + #endif + + /* And of course, our negotiated algorithms */ + rsp->payload.open_session_response.auth_alg = rsp->data[offset + 16]; + rsp->payload.open_session_response.integrity_alg = rsp->data[offset + 24]; + rsp->payload.open_session_response.crypt_alg = rsp->data[offset + 32]; +} + + + +/* + * read_rakp2_message + * + * Initialize the ipmi_rs from the IPMI 2.x RAKP 2 message + * + * The offset should point the first byte of the the RAKP 2 payload when this + * function is called. + * + * param rsp [in/out] reading from the data variable and writing to the rakp 2 + * section + * param offset [in] tells us where hte rakp2 payload starts + * param auth_alg [in] describes the authentication algorithm was agreed upon in + * the open session request/response phase. We need to know that here so + * that we know how many bytes (if any) to read fromt the packet. + * + * returns 0 on success, 1 on error + */ +void +read_rakp2_message( + struct ipmi_rs * rsp, + int offset, + uint8_t auth_alg) +{ + int i; + + /* Message tag */ + rsp->payload.rakp2_message.message_tag = rsp->data[offset]; + + /* RAKP reponse code */ + rsp->payload.rakp2_message.rakp_return_code = rsp->data[offset + 1]; + + /* Console session ID */ + memcpy(&(rsp->payload.rakp2_message.console_id), + rsp->data + offset + 4, + 4); + #if WORDS_BIGENDIAN + rsp->payload.rakp2_message.console_id = + BSWAP_32(rsp->payload.rakp2_message.console_id); + #endif + + /* BMC random number */ + memcpy(&(rsp->payload.rakp2_message.bmc_rand), + rsp->data + offset + 8, + 16); + #if WORDS_BIGENDIAN + lanplus_swap(rsp->payload.rakp2_message.bmc_rand, 16); + #endif + + /* BMC GUID */ + memcpy(&(rsp->payload.rakp2_message.bmc_guid), + rsp->data + offset + 24, + 16); + #if WORDS_BIGENDIAN + lanplus_swap(rsp->payload.rakp2_message.bmc_guid, 16); + #endif + + /* Key exchange authentication code */ + switch (auth_alg) + { + case IPMI_AUTH_RAKP_NONE: + /* Nothing to do here */ + break; + + case IPMI_AUTH_RAKP_HMAC_SHA1: + /* We need to copy 20 bytes */ + for (i = 0; i < 20; ++i) + rsp->payload.rakp2_message.key_exchange_auth_code[i] = + rsp->data[offset + 40 + i]; + break; + + case IPMI_AUTH_RAKP_HMAC_MD5: + lprintf(LOG_ERR, "read_rakp2_message: no support for " + "IPMI_AUTH_RAKP_HMAC_MD5"); + assert(0); + break; + } +} + + + +/* + * read_rakp4_message + * + * Initialize the ipmi_rs from the IPMI 2.x RAKP 4 message + * + * The offset should point the first byte of the the RAKP 4 payload when this + * function is called. + * + * param rsp [in/out] reading from the data variable and writing to the rakp + * 4 section + * param offset [in] tells us where hte rakp4 payload starts + * param integrity_alg [in] describes the authentication algorithm was + * agreed upon in the open session request/response phase. We need + * to know that here so that we know how many bytes (if any) to read + * from the packet. + * + * returns 0 on success, 1 on error + */ +void +read_rakp4_message( + struct ipmi_rs * rsp, + int offset, + uint8_t auth_alg) +{ + int i; + + /* Message tag */ + rsp->payload.rakp4_message.message_tag = rsp->data[offset]; + + /* RAKP reponse code */ + rsp->payload.rakp4_message.rakp_return_code = rsp->data[offset + 1]; + + /* Console session ID */ + memcpy(&(rsp->payload.rakp4_message.console_id), + rsp->data + offset + 4, + 4); + #if WORDS_BIGENDIAN + rsp->payload.rakp4_message.console_id = + BSWAP_32(rsp->payload.rakp4_message.console_id); + #endif + + + /* Integrity check value */ + switch (auth_alg) + { + case IPMI_AUTH_RAKP_NONE: + /* Nothing to do here */ + break; + + case IPMI_AUTH_RAKP_HMAC_SHA1: + /* We need to copy 12 bytes */ + for (i = 0; i < 12; ++i) + rsp->payload.rakp4_message.integrity_check_value[i] = + rsp->data[offset + 8 + i]; + break; + + case IPMI_AUTH_RAKP_HMAC_MD5: + lprintf(LOG_ERR, "read_rakp4_message: no support " + "for authentication algorithm 0x%x", auth_alg); + assert(0); + break; + } +} + + + + +/* + * read_session_data + * + * Initialize the ipmi_rsp from the session data in the packet + * + * The offset should point the first byte of the the IPMI session when this + * function is called. + * + * param rsp [in/out] we read from the data buffer and populate the session + * specific fields. + * param offset [in/out] should point to the beginning of the session when + * this function is called. The offset will be adjusted to + * point to the end of the session when this function exits. + * param session holds our session state + */ +void +read_session_data( + struct ipmi_rs * rsp, + int * offset, + struct ipmi_session * s) +{ + /* We expect to read different stuff depending on the authtype */ + rsp->session.authtype = rsp->data[*offset]; + + if (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) + read_session_data_v2x(rsp, offset, s); + else + read_session_data_v15(rsp, offset, s); +} + + + +/* + * read_session_data_v2x + * + * Initialize the ipmi_rsp from the v2.x session header of the packet. + * + * The offset should point to the first byte of the the IPMI session when this + * function is called. When this function exits, offset will point to the + * start of payload. + * + * Should decrypt and perform integrity checking here? + * + * param rsp [in/out] we read from the data buffer and populate the session + * specific fields. + * param offset [in/out] should point to the beginning of the session when this + * function is called. The offset will be adjusted to point to + * the end of the session when this function exits. + * param s holds our session state + */ +void +read_session_data_v2x( + struct ipmi_rs * rsp, + int * offset, + struct ipmi_session * s) +{ + rsp->session.authtype = rsp->data[(*offset)++]; + + rsp->session.bEncrypted = (rsp->data[*offset] & 0x80 ? 1 : 0); + rsp->session.bAuthenticated = (rsp->data[*offset] & 0x40 ? 1 : 0); + + + /* Payload type */ + rsp->session.payloadtype = rsp->data[(*offset)++] & 0x3F; + + /* Session ID */ + memcpy(&rsp->session.id, rsp->data + *offset, 4); + *offset += 4; + #if WORDS_BIGENDIAN + rsp->session.id = BSWAP_32(rsp->session.id); + #endif + + + /* + * Verify that the session ID is what we think it should be + */ + if ((s->v2_data.session_state == LANPLUS_STATE_ACTIVE) && + (rsp->session.id != s->v2_data.console_id)) + { + lprintf(LOG_ERR, "packet session id 0x%x does not " + "match active session 0x%0x", + rsp->session.id, s->v2_data.console_id); + assert(0); + } + + + /* Ignored, so far */ + memcpy(&rsp->session.seq, rsp->data + *offset, 4); + *offset += 4; + #if WORDS_BIGENDIAN + rsp->session.seq = BSWAP_32(rsp->session.seq); + #endif + + memcpy(&rsp->session.msglen, rsp->data + *offset, 2); + *offset += 2; + #if WORDS_BIGENDIAN + rsp->session.msglen = BSWAP_16(rsp->session.msglen); + #endif +} + + + +/* + * read_session_data_v15 + * + * Initialize the ipmi_rsp from the session header of the packet. + * + * The offset should point the first byte of the the IPMI session when this + * function is called. When this function exits, the offset will point to + * the start of the IPMI message. + * + * param rsp [in/out] we read from the data buffer and populate the session + * specific fields. + * param offset [in/out] should point to the beginning of the session when this + * function is called. The offset will be adjusted to point to the + * end of the session when this function exits. + * param s holds our session state + */ +void read_session_data_v15( + struct ipmi_rs * rsp, + int * offset, + struct ipmi_session * s) +{ + /* All v15 messages are IPMI messages */ + rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_IPMI; + + rsp->session.authtype = rsp->data[(*offset)++]; + + /* All v15 messages that we will receive are unencrypted/unauthenticated */ + rsp->session.bEncrypted = 0; + rsp->session.bAuthenticated = 0; + + /* skip the session id and sequence number fields */ + *offset += 8; + + /* This is the size of the whole payload */ + rsp->session.msglen = rsp->data[(*offset)++]; +} + + + +/* + * read_ipmi_response + * + * Initialize the ipmi_rs from with the IPMI response specific data + * + * The offset should point the first byte of the the IPMI payload when this + * function is called. + * + * param rsp [in/out] we read from the data buffer and populate the IPMI + * specific fields. + * param offset [in/out] should point to the beginning of the IPMI payload when + * this function is called. + */ +void read_ipmi_response(struct ipmi_rs * rsp, int * offset) +{ + /* + * The data here should be decrypted by now. + */ + rsp->payload.ipmi_response.rq_addr = rsp->data[(*offset)++]; + rsp->payload.ipmi_response.netfn = rsp->data[*offset] >> 2; + rsp->payload.ipmi_response.rq_lun = rsp->data[(*offset)++] & 0x3; + (*offset)++; /* checksum */ + rsp->payload.ipmi_response.rs_addr = rsp->data[(*offset)++]; + rsp->payload.ipmi_response.rq_seq = rsp->data[*offset] >> 2; + rsp->payload.ipmi_response.rs_lun = rsp->data[(*offset)++] & 0x3; + rsp->payload.ipmi_response.cmd = rsp->data[(*offset)++]; + rsp->ccode = rsp->data[(*offset)++]; + +} + + + +/* + * read_sol_packet + * + * Initialize the ipmi_rs with the SOL response data + * + * The offset should point the first byte of the the SOL payload when this + * function is called. + * + * param rsp [in/out] we read from the data buffer and populate the + * SOL specific fields. + * param offset [in/out] should point to the beginning of the SOL payload + * when this function is called. + */ +void read_sol_packet(struct ipmi_rs * rsp, int * offset) +{ + + /* + * The data here should be decrypted by now. + */ + rsp->payload.sol_packet.packet_sequence_number = + rsp->data[(*offset)++] & 0x0F; + + rsp->payload.sol_packet.acked_packet_number = + rsp->data[(*offset)++] & 0x0F; + + rsp->payload.sol_packet.accepted_character_count = + rsp->data[(*offset)++]; + + rsp->payload.sol_packet.is_nack = + rsp->data[*offset] & 0x40; + + rsp->payload.sol_packet.transfer_unavailable = + rsp->data[*offset] & 0x20; + + rsp->payload.sol_packet.sol_inactive = + rsp->data[*offset] & 0x10; + + rsp->payload.sol_packet.transmit_overrun = + rsp->data[*offset] & 0x08; + + rsp->payload.sol_packet.break_detected = + rsp->data[(*offset)++] & 0x04; + + lprintf(LOG_DEBUG, "<<<<<<<<<< RECV FROM BMC <<<<<<<<<<<"); + lprintf(LOG_DEBUG, "< SOL sequence number : 0x%02x", + rsp->payload.sol_packet.packet_sequence_number); + lprintf(LOG_DEBUG, "< SOL acked packet : 0x%02x", + rsp->payload.sol_packet.acked_packet_number); + lprintf(LOG_DEBUG, "< SOL accepted char count : 0x%02x", + rsp->payload.sol_packet.accepted_character_count); + lprintf(LOG_DEBUG, "< SOL is nack : %s", + rsp->payload.sol_packet.is_nack? "true" : "false"); + lprintf(LOG_DEBUG, "< SOL xfer unavailable : %s", + rsp->payload.sol_packet.transfer_unavailable? "true" : "false"); + lprintf(LOG_DEBUG, "< SOL inactive : %s", + rsp->payload.sol_packet.sol_inactive? "true" : "false"); + lprintf(LOG_DEBUG, "< SOL transmit overrun : %s", + rsp->payload.sol_packet.transmit_overrun? "true" : "false"); + lprintf(LOG_DEBUG, "< SOL break detected : %s", + rsp->payload.sol_packet.break_detected? "true" : "false"); + lprintf(LOG_DEBUG, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); + + if (verbose >= 5) + printbuf(rsp->data + *offset - 4, 4, "SOL MSG FROM BMC"); +} + + + +/* + * getIpmiPayloadWireRep + * + * param out [out] will contain our wire representation + * param req [in] is the IPMI request to be written + * param crypt_alg [in] specifies the encryption to use + * param rq_seq [in] is the IPMI command sequence number. + */ +void getIpmiPayloadWireRep( + struct ipmi_intf * intf, /* in out */ + struct ipmi_v2_payload * payload, /* in */ + uint8_t * msg, + struct ipmi_rq * req, + uint8_t rq_seq, + uint8_t curr_seq) +{ + int cs, tmp, len; + int cs2 = 0; + int cs3 = 0; + uint8_t ourAddress = intf->my_addr; + uint8_t bridgedRequest = 0; + + if (ourAddress == 0) + ourAddress = IPMI_BMC_SLAVE_ADDR; + + len = 0; + + /* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */ + if ((intf->target_addr == ourAddress) || (!bridgePossible)) { + cs = len; + } else { + bridgedRequest = 1; + + if(intf->transit_addr != ourAddress && intf->transit_addr != 0) + { + bridgedRequest++; + } + /* bridged request: encapsulate w/in Send Message */ + cs = len; + msg[len++] = IPMI_BMC_SLAVE_ADDR; + msg[len++] = IPMI_NETFN_APP << 2; + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs2 = len; + msg[len++] = IPMI_REMOTE_SWID; + msg[len++] = curr_seq << 2; + + + msg[len++] = 0x34; /* Send Message rqst */ + if(bridgedRequest == 2) + msg[len++] = (0x40|intf->transit_channel); /* Track request*/ + else + msg[len++] = (0x40|intf->target_channel); /* Track request*/ + + payload->payload_length += 7; + cs = len; + + if(bridgedRequest == 2) + { + /* bridged request: encapsulate w/in Send Message */ + cs = len; + msg[len++] = intf->transit_addr; + msg[len++] = IPMI_NETFN_APP << 2; + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs3 = len; + msg[len++] = intf->my_addr; + msg[len++] = curr_seq << 2; + msg[len++] = 0x34; /* Send Message rqst */ + #if 0 /* From lan.c example */ + entry->req.msg.target_cmd = entry->req.msg.cmd; /* Save target command */ + entry->req.msg.cmd = 0x34; /* (fixup request entry) */ + #endif + msg[len++] = (0x40|intf->target_channel); /* Track request*/ + + payload->payload_length += 7; + + cs = len; + } + } + + lprintf(LOG_DEBUG,"%s RqAddr %#x transit %#x:%#x target %#x:%#x " + "bridgePossible %d", + bridgedRequest ? "Bridging" : "Local", + intf->my_addr, intf->transit_addr, intf->transit_channel, + intf->target_addr, intf->target_channel, + bridgePossible); + + /* rsAddr */ + msg[len++] = intf->target_addr; /* IPMI_BMC_SLAVE_ADDR; */ + + /* net Fn */ + msg[len++] = req->msg.netfn << 2 | (req->msg.lun & 3); + tmp = len - cs; + + /* checkSum */ + msg[len++] = ipmi_csum(msg+cs, tmp); + cs = len; + + /* rqAddr */ + if (!bridgedRequest) + msg[len++] = IPMI_REMOTE_SWID; + else /* Bridged message */ + msg[len++] = intf->my_addr; + + /* rqSeq / rqLUN */ + msg[len++] = rq_seq << 2; + + /* cmd */ + msg[len++] = req->msg.cmd; + + /* message data */ + if (req->msg.data_len) { + memcpy(msg + len, req->msg.data, req->msg.data_len); + len += req->msg.data_len; + } + + /* second checksum */ + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + + /* Dual bridged request: 2nd checksum */ + if (bridgedRequest == 2) { + tmp = len - cs3; + msg[len++] = ipmi_csum(msg+cs3, tmp); + payload->payload_length += 1; + } + + /* bridged request: 2nd checksum */ + if (bridgedRequest) { + tmp = len - cs2; + msg[len++] = ipmi_csum(msg+cs2, tmp); + payload->payload_length += 1; + } +} + + + +/* + * getSolPayloadWireRep + * + * param msg [out] will contain our wire representation + * param payload [in] holds the v2 payload with our SOL data + */ +void getSolPayloadWireRep( + struct ipmi_intf * intf, /* in out */ + uint8_t * msg, /* output */ + struct ipmi_v2_payload * payload) /* input */ +{ + int i = 0; + + lprintf(LOG_DEBUG, ">>>>>>>>>> SENDING TO BMC >>>>>>>>>>"); + lprintf(LOG_DEBUG, "> SOL sequence number : 0x%02x", + payload->payload.sol_packet.packet_sequence_number); + lprintf(LOG_DEBUG, "> SOL acked packet : 0x%02x", + payload->payload.sol_packet.acked_packet_number); + lprintf(LOG_DEBUG, "> SOL accepted char count : 0x%02x", + payload->payload.sol_packet.accepted_character_count); + lprintf(LOG_DEBUG, "> SOL is nack : %s", + payload->payload.sol_packet.is_nack ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL assert ring wor : %s", + payload->payload.sol_packet.assert_ring_wor ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL generate break : %s", + payload->payload.sol_packet.generate_break ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL deassert cts : %s", + payload->payload.sol_packet.deassert_cts ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL deassert dcd dsr : %s", + payload->payload.sol_packet.deassert_dcd_dsr ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL flush inbound : %s", + payload->payload.sol_packet.flush_inbound ? "true" : "false"); + lprintf(LOG_DEBUG, "> SOL flush outbound : %s", + payload->payload.sol_packet.flush_outbound ? "true" : "false"); + + msg[i++] = payload->payload.sol_packet.packet_sequence_number; + msg[i++] = payload->payload.sol_packet.acked_packet_number; + msg[i++] = payload->payload.sol_packet.accepted_character_count; + + msg[i] = payload->payload.sol_packet.is_nack ? 0x40 : 0; + msg[i] |= payload->payload.sol_packet.assert_ring_wor ? 0x20 : 0; + msg[i] |= payload->payload.sol_packet.generate_break ? 0x10 : 0; + msg[i] |= payload->payload.sol_packet.deassert_cts ? 0x08 : 0; + msg[i] |= payload->payload.sol_packet.deassert_dcd_dsr ? 0x04 : 0; + msg[i] |= payload->payload.sol_packet.flush_inbound ? 0x02 : 0; + msg[i++] |= payload->payload.sol_packet.flush_outbound ? 0x01 : 0; + + /* We may have data to add */ + memcpy(msg + i, + payload->payload.sol_packet.data, + payload->payload.sol_packet.character_count); + + lprintf(LOG_DEBUG, "> SOL character count : %d", + payload->payload.sol_packet.character_count); + lprintf(LOG_DEBUG, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); + + if (verbose >= 5 && payload->payload.sol_packet.character_count) + printbuf(payload->payload.sol_packet.data, payload->payload.sol_packet.character_count, "SOL SEND DATA"); + + /* + * At this point, the payload length becomes the whole payload + * length, including the 4 bytes at the beginning of the SOL + * packet + */ + payload->payload_length = payload->payload.sol_packet.character_count + 4; +} + + + +/* + * ipmi_lanplus_build_v2x_msg + * + * Encapsulates the payload data to create the IPMI v2.0 / RMCP+ packet. + * + * + * IPMI v2.0 LAN Request Message Format + * +----------------------+ + * | rmcp.ver | 4 bytes + * | rmcp.__reserved | + * | rmcp.seq | + * | rmcp.class | + * +----------------------+ + * | session.authtype | 10 bytes + * | session.payloadtype | + * | session.id | + * | session.seq | + * +----------------------+ + * | message length | 2 bytes + * +----------------------+ + * | Confidentiality Hdr | var (possibly absent) + * +----------------------+ + * | Paylod | var Payload + * +----------------------+ + * | Confidentiality Trlr | var (possibly absent) + * +----------------------+ + * | Integrity pad | var (possibly absent) + * +----------------------+ + * | Pad length | 1 byte (WTF?) + * +----------------------+ + * | Next Header | 1 byte (WTF?) + * +----------------------+ + * | Authcode | var (possibly absent) + * +----------------------+ + */ +void +ipmi_lanplus_build_v2x_msg( + struct ipmi_intf * intf, /* in */ + struct ipmi_v2_payload * payload, /* in */ + int * msg_len, /* out */ + uint8_t ** msg_data, /* out */ + uint8_t curr_seq) +{ + uint32_t session_trailer_length = 0; + struct ipmi_session * session = intf->session; + struct rmcp_hdr rmcp = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_IPMI, + .seq = 0xff, + }; + + /* msg will hold the entire message to be sent */ + uint8_t * msg; + int len = 0; + + + len = + sizeof(rmcp) + // RMCP Header (4) + 10 + // IPMI Session Header + 2 + // Message length + payload->payload_length + // The actual payload + IPMI_MAX_INTEGRITY_PAD_SIZE + // Integrity Pad + 1 + // Pad Length + 1 + // Next Header + IPMI_MAX_AUTH_CODE_SIZE; // Authcode + + + msg = malloc(len); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return; + } + memset(msg, 0, len); + + /* + *------------------------------------------ + * RMCP HEADER + *------------------------------------------ + */ + memcpy(msg, &rmcp, sizeof(rmcp)); + len = sizeof(rmcp); + + + /* + *------------------------------------------ + * IPMI SESSION HEADER + *------------------------------------------ + */ + /* ipmi session Auth Type / Format is always 0x06 for IPMI v2 */ + msg[IPMI_LANPLUS_OFFSET_AUTHTYPE] = 0x06; + + /* Payload Type -- also specifies whether were authenticated/encyrpted */ + msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] = payload->payload_type; + + if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE) + { + msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] |= + ((session->v2_data.crypt_alg != IPMI_CRYPT_NONE )? 0x80 : 0x00); + msg[IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE] |= + ((session->v2_data.integrity_alg != IPMI_INTEGRITY_NONE)? 0x40 : 0x00); + } + + if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE) + { + /* Session ID -- making it LSB */ + msg[IPMI_LANPLUS_OFFSET_SESSION_ID ] = session->v2_data.bmc_id & 0xff; + msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 1] = (session->v2_data.bmc_id >> 8) & 0xff; + msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 2] = (session->v2_data.bmc_id >> 16) & 0xff; + msg[IPMI_LANPLUS_OFFSET_SESSION_ID + 3] = (session->v2_data.bmc_id >> 24) & 0xff; + + /* Sequence Number -- making it LSB */ + msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM ] = session->out_seq & 0xff; + msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 1] = (session->out_seq >> 8) & 0xff; + msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 2] = (session->out_seq >> 16) & 0xff; + msg[IPMI_LANPLUS_OFFSET_SEQUENCE_NUM + 3] = (session->out_seq >> 24) & 0xff; + } + + /* + * Payload Length is set below (we don't know how big the payload is until after + * encryption). + */ + + /* + * Payload + * + * At this point we are ready to slam the payload in. + * This includes: + * 1) The confidentiality header + * 2) The payload proper (possibly encrypted) + * 3) The confidentiality trailer + * + */ + switch (payload->payload_type) + { + case IPMI_PAYLOAD_TYPE_IPMI: + getIpmiPayloadWireRep(intf, + payload, /* in */ + msg + IPMI_LANPLUS_OFFSET_PAYLOAD, + payload->payload.ipmi_request.request, + payload->payload.ipmi_request.rq_seq, + curr_seq); + break; + + case IPMI_PAYLOAD_TYPE_SOL: + getSolPayloadWireRep(intf, + msg + IPMI_LANPLUS_OFFSET_PAYLOAD, + payload); + + if (verbose >= 5) + printbuf(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, 4, "SOL MSG TO BMC"); + + len += payload->payload_length; + + break; + + case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST: + /* never encrypted, so our job is easy */ + memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, + payload->payload.open_session_request.request, + payload->payload_length); + len += payload->payload_length; + break; + + case IPMI_PAYLOAD_TYPE_RAKP_1: + /* never encrypted, so our job is easy */ + memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, + payload->payload.rakp_1_message.message, + payload->payload_length); + len += payload->payload_length; + break; + + case IPMI_PAYLOAD_TYPE_RAKP_3: + /* never encrypted, so our job is easy */ + memcpy(msg + IPMI_LANPLUS_OFFSET_PAYLOAD, + payload->payload.rakp_3_message.message, + payload->payload_length); + len += payload->payload_length; + break; + + default: + lprintf(LOG_ERR, "unsupported payload type 0x%x", + payload->payload_type); + free(msg); + msg = NULL; + assert(0); + break; + } + + + /* + *------------------------------------------ + * ENCRYPT THE PAYLOAD IF NECESSARY + *------------------------------------------ + */ + if (session->v2_data.session_state == LANPLUS_STATE_ACTIVE) + { + /* Payload len is adjusted as necessary by lanplus_encrypt_payload */ + lanplus_encrypt_payload(session->v2_data.crypt_alg, /* input */ + session->v2_data.k2, /* input */ + msg + IPMI_LANPLUS_OFFSET_PAYLOAD, /* input */ + payload->payload_length, /* input */ + msg + IPMI_LANPLUS_OFFSET_PAYLOAD, /* output */ + &(payload->payload_length)); /* output */ + + } + + /* Now we know the payload length */ + msg[IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE ] = + payload->payload_length & 0xff; + msg[IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE + 1] = + (payload->payload_length >> 8) & 0xff; + + + /* + *------------------------------------------ + * SESSION TRAILER + *------------------------------------------ + */ + if ((session->v2_data.session_state == LANPLUS_STATE_ACTIVE) && + (session->v2_data.integrity_alg != IPMI_INTEGRITY_NONE)) + { + uint32_t i, hmac_length, integrity_pad_size = 0, hmac_input_size; + uint8_t * hmac_output; + uint32_t start_of_session_trailer = + IPMI_LANPLUS_OFFSET_PAYLOAD + + payload->payload_length; + + + /* + * Determine the required integrity pad length. We have to make the + * data range covered by the authcode a multiple of 4. + */ + uint32_t length_before_authcode; + + if (ipmi_oem_active(intf, "icts")) { + length_before_authcode = + 12 + /* the stuff before the payload */ + payload->payload_length; + } else { + length_before_authcode = + 12 + /* the stuff before the payload */ + payload->payload_length + + 1 + /* pad length field */ + 1; /* next header field */ + } + + if (length_before_authcode % 4) + integrity_pad_size = 4 - (length_before_authcode % 4); + + for (i = 0; i < integrity_pad_size; ++i) + msg[start_of_session_trailer + i] = 0xFF; + + /* Pad length */ + msg[start_of_session_trailer + integrity_pad_size] = integrity_pad_size; + + /* Next Header */ + msg[start_of_session_trailer + integrity_pad_size + 1] = + 0x07; /* Hardcoded per the spec, table 13-8 */ + + hmac_input_size = + 12 + + payload->payload_length + + integrity_pad_size + + 2; + + hmac_output = + msg + + IPMI_LANPLUS_OFFSET_PAYLOAD + + payload->payload_length + + integrity_pad_size + + 2; + + if (verbose > 2) + printbuf(msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, hmac_input_size, "authcode input"); + + + /* Auth Code */ + lanplus_HMAC(session->v2_data.integrity_alg, + session->v2_data.k1, /* key */ + 20, /* key length */ + msg + IPMI_LANPLUS_OFFSET_AUTHTYPE, /* hmac input */ + hmac_input_size, + hmac_output, + &hmac_length); + + assert(hmac_length == 20); + + if (verbose > 2) + printbuf(hmac_output, 12, "authcode output"); + + /* Set session_trailer_length appropriately */ + session_trailer_length = + integrity_pad_size + + 2 + /* pad length + next header */ + 12; /* Size of the authcode (we only use the first 12 bytes) */ + } + + + ++(session->out_seq); + if (!session->out_seq) + ++(session->out_seq); + + *msg_len = + IPMI_LANPLUS_OFFSET_PAYLOAD + + payload->payload_length + + session_trailer_length; + *msg_data = msg; +} + + + +/* + * ipmi_lanplus_build_v2x_ipmi_cmd + * + * Wraps ipmi_lanplus_build_v2x_msg and returns a new entry object for the + * command + * + */ +static struct ipmi_rq_entry * +ipmi_lanplus_build_v2x_ipmi_cmd( + struct ipmi_intf * intf, + struct ipmi_rq * req, + int isRetry) +{ + struct ipmi_v2_payload v2_payload; + struct ipmi_rq_entry * entry; + + /* + * We have a problem. we need to know the sequence number here, + * because we use it in our stored entry. But we also need to + * know the sequence number when we generate our IPMI + * representation far below. + */ + static uint8_t curr_seq = 0; + + if( isRetry == 0 ) + curr_seq += 1; + + if (curr_seq >= 64) + curr_seq = 0; + + + /* IPMI Message Header -- Figure 13-4 of the IPMI v2.0 spec */ + if ((intf->target_addr == intf->my_addr) || (!bridgePossible)) + { + entry = ipmi_req_add_entry(intf, req, curr_seq); + } + else /* it's a bridge command */ + { + unsigned char backup_cmd; + + /* Add entry for cmd */ + entry = ipmi_req_add_entry(intf, req, curr_seq); + + if(entry) + { + /* Add entry for bridge cmd */ + backup_cmd = req->msg.cmd; + req->msg.cmd = 0x34; + entry = ipmi_req_add_entry(intf, req, curr_seq); + req->msg.cmd = backup_cmd; + } + } + + if (entry == NULL) + return NULL; + + // Build our payload + v2_payload.payload_type = IPMI_PAYLOAD_TYPE_IPMI; + v2_payload.payload_length = req->msg.data_len + 7; + v2_payload.payload.ipmi_request.request = req; + v2_payload.payload.ipmi_request.rq_seq = curr_seq; + + ipmi_lanplus_build_v2x_msg(intf, // in + &v2_payload, // in + &(entry->msg_len), // out + &(entry->msg_data), // out + curr_seq); // in + + return entry; +} + + + + + +/* + * IPMI LAN Request Message Format + * +--------------------+ + * | rmcp.ver | 4 bytes + * | rmcp.__reserved | + * | rmcp.seq | + * | rmcp.class | + * +--------------------+ + * | session.authtype | 9 bytes + * | session.seq | + * | session.id | + * +--------------------+ + * | [session.authcode] | 16 bytes (AUTHTYPE != none) + * +--------------------+ + * | message length | 1 byte + * +--------------------+ + * | message.rs_addr | 6 bytes + * | message.netfn_lun | + * | message.checksum | + * | message.rq_addr | + * | message.rq_seq | + * | message.cmd | + * +--------------------+ + * | [request data] | data_len bytes + * +--------------------+ + * | checksum | 1 byte + * +--------------------+ + */ +static struct ipmi_rq_entry * +ipmi_lanplus_build_v15_ipmi_cmd( + struct ipmi_intf * intf, + struct ipmi_rq * req) +{ + struct rmcp_hdr rmcp = { + .ver = RMCP_VERSION_1, + .class = RMCP_CLASS_IPMI, + .seq = 0xff, + }; + uint8_t * msg; + int cs, mp, len = 0, tmp; + struct ipmi_session * session = intf->session; + struct ipmi_rq_entry * entry; + + entry = ipmi_req_add_entry(intf, req, 0); + if (entry == NULL) + return NULL; + + len = req->msg.data_len + 21; + + msg = malloc(len); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + memset(msg, 0, len); + + /* rmcp header */ + memcpy(msg, &rmcp, sizeof(rmcp)); + len = sizeof(rmcp); + + /* + * ipmi session header + */ + /* Authtype should always be none for 1.5 packets sent from this + * interface + */ + msg[len++] = IPMI_SESSION_AUTHTYPE_NONE; + + msg[len++] = session->out_seq & 0xff; + msg[len++] = (session->out_seq >> 8) & 0xff; + msg[len++] = (session->out_seq >> 16) & 0xff; + msg[len++] = (session->out_seq >> 24) & 0xff; + + /* + * The session ID should be all zeroes for pre-session commands. We + * should only be using the 1.5 interface for the pre-session Get + * Channel Authentication Capabilities command + */ + msg[len++] = 0; + msg[len++] = 0; + msg[len++] = 0; + msg[len++] = 0; + + /* message length */ + msg[len++] = req->msg.data_len + 7; + + /* ipmi message header */ + cs = mp = len; + msg[len++] = IPMI_BMC_SLAVE_ADDR; + msg[len++] = req->msg.netfn << 2; + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + cs = len; + msg[len++] = IPMI_REMOTE_SWID; + + entry->rq_seq = 0; + + msg[len++] = entry->rq_seq << 2; + msg[len++] = req->msg.cmd; + + lprintf(LOG_DEBUG+1, ">> IPMI Request Session Header"); + lprintf(LOG_DEBUG+1, ">> Authtype : %s", + val2str(IPMI_SESSION_AUTHTYPE_NONE, ipmi_authtype_session_vals)); + lprintf(LOG_DEBUG+1, ">> Sequence : 0x%08lx", + (long)session->out_seq); + lprintf(LOG_DEBUG+1, ">> Session ID : 0x%08lx", + (long)0); + + lprintf(LOG_DEBUG+1, ">> IPMI Request Message Header"); + lprintf(LOG_DEBUG+1, ">> Rs Addr : %02x", IPMI_BMC_SLAVE_ADDR); + lprintf(LOG_DEBUG+1, ">> NetFn : %02x", req->msg.netfn); + lprintf(LOG_DEBUG+1, ">> Rs LUN : %01x", 0); + lprintf(LOG_DEBUG+1, ">> Rq Addr : %02x", IPMI_REMOTE_SWID); + lprintf(LOG_DEBUG+1, ">> Rq Seq : %02x", entry->rq_seq); + lprintf(LOG_DEBUG+1, ">> Rq Lun : %01x", 0); + lprintf(LOG_DEBUG+1, ">> Command : %02x", req->msg.cmd); + + /* message data */ + if (req->msg.data_len) { + memcpy(msg+len, req->msg.data, req->msg.data_len); + len += req->msg.data_len; + } + + /* second checksum */ + tmp = len - cs; + msg[len++] = ipmi_csum(msg+cs, tmp); + + entry->msg_len = len; + entry->msg_data = msg; + + return entry; +} + + + +/* + * is_sol_packet + */ +static int +is_sol_packet(struct ipmi_rs * rsp) +{ + return (rsp && + (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)); +} + + + +/* + * sol_response_acks_packet + */ +static int +sol_response_acks_packet( + struct ipmi_rs * rsp, + struct ipmi_v2_payload * payload) +{ + return (is_sol_packet(rsp) && + payload && + (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL) && + (rsp->payload.sol_packet.acked_packet_number == + payload->payload.sol_packet.packet_sequence_number)); +} + + + +/* + * ipmi_lanplus_send_payload + * + */ +struct ipmi_rs * +ipmi_lanplus_send_payload( + struct ipmi_intf * intf, + struct ipmi_v2_payload * payload) +{ + struct ipmi_rs * rsp = NULL; + uint8_t * msg_data; + int msg_length; + struct ipmi_session * session = intf->session; + struct ipmi_rq_entry * entry = NULL; + int try = 0; + int xmit = 1; + time_t ltime; + uint32_t saved_timeout; + + if (!intf->opened && intf->open && intf->open(intf) < 0) + return NULL; + + /* + * The session timeout is initialized in the above interface open, + * so it will only be valid after the open completes. + */ + saved_timeout = session->timeout; + while (try < session->retry) { + //ltime = time(NULL); + + if (xmit) { + ltime = time(NULL); + + if (payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI) + { + /* + * Build an IPMI v1.5 or v2 command + */ + struct ipmi_rq * ipmi_request = payload->payload.ipmi_request.request; + + lprintf(LOG_DEBUG, ""); + lprintf(LOG_DEBUG, ">> Sending IPMI command payload"); + lprintf(LOG_DEBUG, ">> netfn : 0x%02x", ipmi_request->msg.netfn); + lprintf(LOG_DEBUG, ">> command : 0x%02x", ipmi_request->msg.cmd); + + if (verbose > 1) + { + uint16_t i; + fprintf(stderr, ">> data : "); + for (i = 0; i < ipmi_request->msg.data_len; ++i) + fprintf(stderr, "0x%02x ", ipmi_request->msg.data[i]); + fprintf(stderr, "\n\n"); + } + + + /* + * If we are presession, and the command is GET CHANNEL AUTHENTICATION + * CAPABILITIES, we will build the command in v1.5 format. This is so + * that we can ask any server whether it supports IPMI v2 / RMCP+ + * before we attempt to open a v2.x session. + */ + if ((ipmi_request->msg.netfn == IPMI_NETFN_APP) && + (ipmi_request->msg.cmd == IPMI_GET_CHANNEL_AUTH_CAP) && + (session->v2_data.bmc_id == 0)) // jme - check + { + lprintf(LOG_DEBUG+1, "BUILDING A v1.5 COMMAND"); + entry = ipmi_lanplus_build_v15_ipmi_cmd(intf, ipmi_request); + } + else + { + int isRetry = ( try > 0 ? 1 : 0 ); + + lprintf(LOG_DEBUG+1, "BUILDING A v2 COMMAND"); + entry = ipmi_lanplus_build_v2x_ipmi_cmd(intf, ipmi_request, isRetry); + } + + if (entry == NULL) { + lprintf(LOG_ERR, "Aborting send command, unable to build"); + return NULL; + } + + msg_data = entry->msg_data; + msg_length = entry->msg_len; + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST) + { + lprintf(LOG_DEBUG, ">> SENDING AN OPEN SESSION REQUEST\n"); + assert(session->v2_data.session_state == LANPLUS_STATE_PRESESSION + || session->v2_data.session_state == LANPLUS_STATE_OPEN_SESSION_SENT); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_1) + { + lprintf(LOG_DEBUG, ">> SENDING A RAKP 1 MESSAGE\n"); + assert(session->v2_data.session_state == + LANPLUS_STATE_OPEN_SESSION_RECEIEVED); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_RAKP_3) + { + lprintf(LOG_DEBUG, ">> SENDING A RAKP 3 MESSAGE\n"); + assert(session->v2_data.session_state == + LANPLUS_STATE_RAKP_2_RECEIVED); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + + } + + else if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL) + { + lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n"); + assert(session->v2_data.session_state == LANPLUS_STATE_ACTIVE); + + ipmi_lanplus_build_v2x_msg(intf, /* in */ + payload, /* in */ + &msg_length, /* out */ + &msg_data, /* out */ + 0); /* irrelevant for this msg*/ + } + + else + { + lprintf(LOG_ERR, "Payload type 0x%0x is unsupported!", + payload->payload_type); + assert(0); + } + + + if (ipmi_lan_send_packet(intf, msg_data, msg_length) < 0) { + lprintf(LOG_ERR, "IPMI LAN send command failed"); + return NULL; + } + } + + /* if we are set to noanswer we do not expect response */ + if (intf->noanswer) + break; + + usleep(100); /* Not sure what this is for */ + + /* Remember our connection state */ + switch (payload->payload_type) + { + case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST: + session->v2_data.session_state = LANPLUS_STATE_OPEN_SESSION_SENT; + /* not retryable for timeouts, force no retry */ + try = session->retry; + break; + case IPMI_PAYLOAD_TYPE_RAKP_1: + session->v2_data.session_state = LANPLUS_STATE_RAKP_1_SENT; + /* not retryable for timeouts, force no retry */ + try = session->retry; + break; + case IPMI_PAYLOAD_TYPE_RAKP_3: + /* not retryable for timeouts, force no retry */ + try = session->retry; + session->v2_data.session_state = LANPLUS_STATE_RAKP_3_SENT; + break; + } + + + /* + * Special case for SOL outbound packets. + */ + if (payload->payload_type == IPMI_PAYLOAD_TYPE_SOL) + { + if (! payload->payload.sol_packet.packet_sequence_number) + { + /* We're just sending an ACK. No need to retry. */ + break; + } + + + rsp = ipmi_lanplus_recv_sol(intf); /* Grab the next packet */ + + if (sol_response_acks_packet(rsp, payload)) + break; + + else if (is_sol_packet(rsp) && rsp->data_len) + { + /* + * We're still waiting for our ACK, but we more data from + * the BMC + */ + intf->session->sol_data.sol_input_handler(rsp); + /* In order to avoid duplicate output, just set data_len to 0 */ + rsp->data_len = 0; + } + } + + + /* Non-SOL processing */ + else + { + rsp = ipmi_lan_poll_recv(intf); + + /* Duplicate Request ccode most likely indicates a response to + a previous retry. Ignore and keep polling. */ + while ((rsp != NULL) && (rsp->ccode == 0xcf)) + { + rsp = NULL; + rsp = ipmi_lan_poll_recv(intf); + } + + if (rsp) + break; + /* This payload type is retryable for timeouts. */ + if ((payload->payload_type == IPMI_PAYLOAD_TYPE_IPMI) && entry) { + ipmi_req_remove_entry( entry->rq_seq, entry->req.msg.cmd); + } + } + + /* only timeout if time exceeds the timeout value */ + xmit = ((time(NULL) - ltime) >= session->timeout); + + usleep(5000); + + if (xmit) { + /* increment session timeout by 1 second each retry */ + session->timeout++; + } + + try++; + } + session->timeout = saved_timeout; + + /* IPMI messages are deleted under ipmi_lan_poll_recv() */ + switch (payload->payload_type) { + case IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST: + case IPMI_PAYLOAD_TYPE_RAKP_1: + case IPMI_PAYLOAD_TYPE_RAKP_3: + free(msg_data); + msg_data = NULL; + break; + } + + return rsp; +} + + + +/* + * is_sol_partial_ack + * + * Determine if the response is a partial ACK/NACK that indicates + * we need to resend part of our packet. + * + * returns the number of characters we need to resend, or + * 0 if this isn't an ACK or we don't need to resend anything + */ +int is_sol_partial_ack( + struct ipmi_intf * intf, + struct ipmi_v2_payload * v2_payload, + struct ipmi_rs * rs) +{ + int chars_to_resend = 0; + + if (v2_payload && + rs && + is_sol_packet(rs) && + sol_response_acks_packet(rs, v2_payload) && + (rs->payload.sol_packet.accepted_character_count < + v2_payload->payload.sol_packet.character_count)) + { + if (ipmi_oem_active(intf, "intelplus") && + rs->payload.sol_packet.accepted_character_count == 0) + return 0; + + chars_to_resend = + v2_payload->payload.sol_packet.character_count - + rs->payload.sol_packet.accepted_character_count; + } + + return chars_to_resend; +} + + + +/* + * set_sol_packet_sequence_number + */ +static void set_sol_packet_sequence_number( + struct ipmi_intf * intf, + struct ipmi_v2_payload * v2_payload) +{ + /* Keep our sequence number sane */ + if (intf->session->sol_data.sequence_number > 0x0F) + intf->session->sol_data.sequence_number = 1; + + v2_payload->payload.sol_packet.packet_sequence_number = + intf->session->sol_data.sequence_number++; +} + + + +/* + * ipmi_lanplus_send_sol + * + * Sends a SOL packet.. We handle partial ACK/NACKs from the BMC here. + * + * Returns a pointer to the SOL ACK we received, or + * 0 on failure + * + */ +struct ipmi_rs * +ipmi_lanplus_send_sol( + struct ipmi_intf * intf, + struct ipmi_v2_payload * v2_payload) +{ + struct ipmi_rs * rs; + + /* + * chars_to_resend indicates either that we got a NACK telling us + * that we need to resend some part of our data. + */ + int chars_to_resend = 0; + + v2_payload->payload_type = IPMI_PAYLOAD_TYPE_SOL; + + /* + * Payload length is just the length of the character + * data here. + */ + v2_payload->payload_length = v2_payload->payload.sol_packet.character_count; + + v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */ + + set_sol_packet_sequence_number(intf, v2_payload); + + v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */ + + rs = ipmi_lanplus_send_payload(intf, v2_payload); + + /* Determine if we need to resend some of our data */ + chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs); + + while (rs && !rs->payload.sol_packet.transfer_unavailable && + !rs->payload.sol_packet.is_nack && + chars_to_resend) + { + /* + * We first need to handle any new data we might have + * received in our NACK + */ + if (rs->data_len) + intf->session->sol_data.sol_input_handler(rs); + + set_sol_packet_sequence_number(intf, v2_payload); + + /* Just send the required data */ + memmove(v2_payload->payload.sol_packet.data, + v2_payload->payload.sol_packet.data + + rs->payload.sol_packet.accepted_character_count, + chars_to_resend); + + v2_payload->payload.sol_packet.character_count = chars_to_resend; + + v2_payload->payload_length = v2_payload->payload.sol_packet.character_count; + + rs = ipmi_lanplus_send_payload(intf, v2_payload); + + chars_to_resend = is_sol_partial_ack(intf, v2_payload, rs); + } + + return rs; +} + + + +/* + * check_sol_packet_for_new_data + * + * Determine whether the SOL packet has already been seen + * and whether the packet has new data for us. + * + * This function has the side effect of removing an previously + * seen data, and moving new data to the front. + * + * It also "Remembers" the data so we don't get repeats. + * + * returns the number of new bytes in the SOL packet + */ +static int +check_sol_packet_for_new_data( + struct ipmi_intf * intf, + struct ipmi_rs *rsp) +{ + static uint8_t last_received_sequence_number = 0; + static uint8_t last_received_byte_count = 0; + int new_data_size = 0; + + + if (rsp && + (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)) + { + /* Store the data length before we mod it */ + uint8_t unaltered_data_len = rsp->data_len; + + if (rsp->payload.sol_packet.packet_sequence_number == + last_received_sequence_number) + { + + /* + * This is the same as the last packet, but may include + * extra data + */ + new_data_size = rsp->data_len - last_received_byte_count; + + if (new_data_size > 0) + { + /* We have more data to process */ + memmove(rsp->data, + rsp->data + + rsp->data_len - new_data_size, + new_data_size); + } + + rsp->data_len = new_data_size; + } + + + /* + *Rember the data for next round + */ + if (rsp->payload.sol_packet.packet_sequence_number) + { + last_received_sequence_number = + rsp->payload.sol_packet.packet_sequence_number; + + last_received_byte_count = unaltered_data_len; + } + } + + + return new_data_size; +} + + + +/* + * ack_sol_packet + * + * Provided the specified packet looks reasonable, ACK it. + */ +static void +ack_sol_packet( + struct ipmi_intf * intf, + struct ipmi_rs * rsp) +{ + if (rsp && + (rsp->session.authtype == IPMI_SESSION_AUTHTYPE_RMCP_PLUS) && + (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) && + (rsp->payload.sol_packet.packet_sequence_number)) + { + struct ipmi_v2_payload ack; + + bzero(&ack, sizeof(struct ipmi_v2_payload)); + + ack.payload_type = IPMI_PAYLOAD_TYPE_SOL; + + /* + * Payload length is just the length of the character + * data here. + */ + ack.payload_length = 0; + + /* ACK packets have sequence numbers of 0 */ + ack.payload.sol_packet.packet_sequence_number = 0; + + ack.payload.sol_packet.acked_packet_number = + rsp->payload.sol_packet.packet_sequence_number; + + ack.payload.sol_packet.accepted_character_count = rsp->data_len; + + ipmi_lanplus_send_payload(intf, &ack); + } +} + + + +/* + * ipmi_lanplus_recv_sol + * + * Receive a SOL packet and send an ACK in response. + * + */ +struct ipmi_rs * +ipmi_lanplus_recv_sol(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf); + + if (rsp && rsp->session.authtype != 0) + { + ack_sol_packet(intf, rsp); + + /* + * Remembers the data sent, and alters the data to just + * include the new stuff. + */ + check_sol_packet_for_new_data(intf, rsp); + } + return rsp; +} + + + +/** + * ipmi_lanplus_send_ipmi_cmd + * + * Build a payload request and dispatch it. + */ +struct ipmi_rs * +ipmi_lanplus_send_ipmi_cmd( + struct ipmi_intf * intf, + struct ipmi_rq * req) +{ + struct ipmi_v2_payload v2_payload; + + v2_payload.payload_type = IPMI_PAYLOAD_TYPE_IPMI; + v2_payload.payload.ipmi_request.request = req; + + return ipmi_lanplus_send_payload(intf, &v2_payload); +} + + +/* + * ipmi_get_auth_capabilities_cmd + * + * This command may have to be sent twice. We first ask for the + * authentication capabilities with the "request IPMI v2 data bit" + * set. If this fails, we send the same command without that bit + * set. + * + * param intf is the initialized (but possibly) pre-session interface + * on which we will send the command + * param auth_cap [out] will be initialized to hold the Get Channel + * Authentication Capabilities return data on success. Its + * contents will be undefined on error. + * + * returns 0 on success + * non-zero if we were unable to contact the BMC, or we cannot + * get a successful response + * + */ +static int +ipmi_get_auth_capabilities_cmd( + struct ipmi_intf * intf, + struct get_channel_auth_cap_rsp * auth_cap) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t msg_data[2]; + uint8_t backupBridgePossible; + + backupBridgePossible = bridgePossible; + + bridgePossible = 0; + + msg_data[0] = IPMI_LAN_CHANNEL_E | 0x80; // Ask for IPMI v2 data as well + msg_data[1] = intf->session->privlvl; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; // 0x06 + req.msg.cmd = IPMI_GET_CHANNEL_AUTH_CAP; // 0x38 + req.msg.data = msg_data; + req.msg.data_len = 2; + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL || rsp->ccode > 0) { + /* + * It's very possible that this failed because we asked for IPMI + * v2 data. Ask again, without requesting IPMI v2 data. + */ + msg_data[0] &= 0x7F; + + rsp = intf->sendrecv(intf, &req); + + if (rsp == NULL) { + lprintf(LOG_INFO, "Get Auth Capabilities error"); + return 1; + } + if (rsp->ccode > 0) { + lprintf(LOG_INFO, "Get Auth Capabilities error: %s", + val2str(rsp->ccode, completion_code_vals)); + return 1; + } + } + + + memcpy(auth_cap, + rsp->data, + sizeof(struct get_channel_auth_cap_rsp)); + + bridgePossible = backupBridgePossible; + + return 0; +} + + + +static int +ipmi_close_session_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t msg_data[4]; + uint32_t bmc_session_lsbf; + uint8_t backupBridgePossible; + + if (intf->session->v2_data.session_state != LANPLUS_STATE_ACTIVE) + return -1; + + backupBridgePossible = bridgePossible; + + intf->target_addr = IPMI_BMC_SLAVE_ADDR; + bridgePossible = 0; + + bmc_session_lsbf = intf->session->v2_data.bmc_id; +#if WORDS_BIGENDIAN + bmc_session_lsbf = BSWAP_32(bmc_session_lsbf); +#endif + + memcpy(&msg_data, &bmc_session_lsbf, 4); + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x3c; + req.msg.data = msg_data; + req.msg.data_len = 4; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + /* Looks like the session was closed */ + lprintf(LOG_ERR, "Close Session command failed"); + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "close_session"); + + if (rsp->ccode == 0x87) { + lprintf(LOG_ERR, "Failed to Close Session: invalid " + "session ID %08lx", + (long)intf->session->v2_data.bmc_id); + return -1; + } + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Close Session command failed: %s", + val2str(rsp->ccode, completion_code_vals)); + return -1; + } + + lprintf(LOG_DEBUG, "Closed Session %08lx\n", + (long)intf->session->v2_data.bmc_id); + + bridgePossible = backupBridgePossible; + + return 0; +} + + + +/* + * ipmi_lanplus_open_session + * + * Build and send the open session command. See section 13.17 of the IPMI + * v2 specification for details. + */ +static int +ipmi_lanplus_open_session(struct ipmi_intf * intf) +{ + struct ipmi_v2_payload v2_payload; + struct ipmi_session * session = intf->session; + uint8_t * msg; + struct ipmi_rs * rsp; + /* 0 = success, 1 = error, 2 = timeout */ + int rc = 0; + + + /* + * Build an Open Session Request Payload + */ + msg = (uint8_t*)malloc(IPMI_OPEN_SESSION_REQUEST_SIZE); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + + memset(msg, 0, IPMI_OPEN_SESSION_REQUEST_SIZE); + + msg[0] = 0; /* Message tag */ + if (ipmi_oem_active(intf, "intelplus") || session->privlvl != IPMI_SESSION_PRIV_ADMIN) + msg[1] = session->privlvl; + else + msg[1] = 0; /* Give us highest privlg level based on supported algorithms */ + msg[2] = 0; /* reserved */ + msg[3] = 0; /* reserved */ + + /* Choose our session ID for easy recognition in the packet dump */ + session->v2_data.console_id = 0xA0A2A3A4; + msg[4] = session->v2_data.console_id & 0xff; + msg[5] = (session->v2_data.console_id >> 8) & 0xff; + msg[6] = (session->v2_data.console_id >> 16) & 0xff; + msg[7] = (session->v2_data.console_id >> 24) & 0xff; + + + if (lanplus_get_requested_ciphers(session->cipher_suite_id, + &(session->v2_data.requested_auth_alg), + &(session->v2_data.requested_integrity_alg), + &(session->v2_data.requested_crypt_alg))) + { + lprintf(LOG_WARNING, "Unsupported cipher suite ID : %d\n", + session->cipher_suite_id); + free(msg); + msg = NULL; + return 1; + } + + + /* + * Authentication payload + */ + msg[8] = 0; /* specifies authentication payload */ + msg[9] = 0; /* reserved */ + msg[10] = 0; /* reserved */ + msg[11] = 8; /* payload length */ + msg[12] = session->v2_data.requested_auth_alg; + msg[13] = 0; /* reserved */ + msg[14] = 0; /* reserved */ + msg[15] = 0; /* reserved */ + + /* + * Integrity payload + */ + msg[16] = 1; /* specifies integrity payload */ + msg[17] = 0; /* reserved */ + msg[18] = 0; /* reserved */ + msg[19] = 8; /* payload length */ + msg[20] = session->v2_data.requested_integrity_alg; + msg[21] = 0; /* reserved */ + msg[22] = 0; /* reserved */ + msg[23] = 0; /* reserved */ + + /* + * Confidentiality/Encryption payload + */ + msg[24] = 2; /* specifies confidentiality payload */ + msg[25] = 0; /* reserved */ + msg[26] = 0; /* reserved */ + msg[27] = 8; /* payload length */ + msg[28] = session->v2_data.requested_crypt_alg; + msg[29] = 0; /* reserved */ + msg[30] = 0; /* reserved */ + msg[31] = 0; /* reserved */ + + + v2_payload.payload_type = IPMI_PAYLOAD_TYPE_RMCP_OPEN_REQUEST; + v2_payload.payload_length = IPMI_OPEN_SESSION_REQUEST_SIZE; + v2_payload.payload.open_session_request.request = msg; + + rsp = ipmi_lanplus_send_payload(intf, &v2_payload); + + free(msg); + msg = NULL; + if (rsp == NULL ) { + lprintf(LOG_DEBUG, "Timeout in open session response message."); + return 2; + } + if (verbose) + lanplus_dump_open_session_response(rsp); + + if (rsp->payload.open_session_response.rakp_return_code != + IPMI_RAKP_STATUS_NO_ERRORS) + { + lprintf(LOG_WARNING, "Error in open session response message : %s\n", + val2str(rsp->payload.open_session_response.rakp_return_code, + ipmi_rakp_return_codes)); + return 1; + } + else + { + if (rsp->payload.open_session_response.console_id != + session->v2_data.console_id) { + lprintf(LOG_WARNING, "Warning: Console session ID is not " + "what we requested"); + } + + session->v2_data.max_priv_level = + rsp->payload.open_session_response.max_priv_level; + session->v2_data.bmc_id = + rsp->payload.open_session_response.bmc_id; + session->v2_data.auth_alg = + rsp->payload.open_session_response.auth_alg; + session->v2_data.integrity_alg = + rsp->payload.open_session_response.integrity_alg; + session->v2_data.crypt_alg = + rsp->payload.open_session_response.crypt_alg; + session->v2_data.session_state = + LANPLUS_STATE_OPEN_SESSION_RECEIEVED; + + + /* + * Verify that we have agreed on a cipher suite + */ + if (rsp->payload.open_session_response.auth_alg != + session->v2_data.requested_auth_alg) + { + lprintf(LOG_WARNING, "Authentication algorithm 0x%02x is " + "not what we requested 0x%02x\n", + rsp->payload.open_session_response.auth_alg, + session->v2_data.requested_auth_alg); + rc = 1; + } + else if (rsp->payload.open_session_response.integrity_alg != + session->v2_data.requested_integrity_alg) + { + lprintf(LOG_WARNING, "Integrity algorithm 0x%02x is " + "not what we requested 0x%02x\n", + rsp->payload.open_session_response.integrity_alg, + session->v2_data.requested_integrity_alg); + rc = 1; + } + else if (rsp->payload.open_session_response.crypt_alg != + session->v2_data.requested_crypt_alg) + { + lprintf(LOG_WARNING, "Encryption algorithm 0x%02x is " + "not what we requested 0x%02x\n", + rsp->payload.open_session_response.crypt_alg, + session->v2_data.requested_crypt_alg); + rc = 1; + } + + } + + return rc; +} + + + +/* + * ipmi_lanplus_rakp1 + * + * Build and send the RAKP 1 message as part of the IPMI v2 / RMCP+ session + * negotiation protocol. We also read and validate the RAKP 2 message received + * from the BMC, here. See section 13.20 of the IPMI v2 specification for + * details. + * + * returns 0 on success + * 1 on failure + * + * Note that failure is only indicated if we have an internal error of + * some kind. If we actually get a RAKP 2 message in response to our + * RAKP 1 message, any errors will be stored in + * session->v2_data.rakp2_return_code and sent to the BMC in the RAKP + * 3 message. + */ +static int +ipmi_lanplus_rakp1(struct ipmi_intf * intf) +{ + struct ipmi_v2_payload v2_payload; + struct ipmi_session * session = intf->session; + uint8_t * msg; + struct ipmi_rs * rsp; + int rc = 0; /* 0 = success, 1 = error, 2 = timeout */ + + /* + * Build a RAKP 1 message + */ + msg = (uint8_t*)malloc(IPMI_RAKP1_MESSAGE_SIZE); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + memset(msg, 0, IPMI_RAKP1_MESSAGE_SIZE); + + + msg[0] = 0; /* Message tag */ + + msg[1] = 0; /* reserved */ + msg[2] = 0; /* reserved */ + msg[3] = 0; /* reserved */ + + /* BMC session ID */ + msg[4] = session->v2_data.bmc_id & 0xff; + msg[5] = (session->v2_data.bmc_id >> 8) & 0xff; + msg[6] = (session->v2_data.bmc_id >> 16) & 0xff; + msg[7] = (session->v2_data.bmc_id >> 24) & 0xff; + + + /* We need a 16 byte random number */ + if (lanplus_rand(session->v2_data.console_rand, 16)) + { + // ERROR; + lprintf(LOG_ERR, "ERROR generating random number " + "in ipmi_lanplus_rakp1"); + free(msg); + msg = NULL; + return 1; + } + memcpy(msg + 8, session->v2_data.console_rand, 16); + #if WORDS_BIGENDIAN + lanplus_swap(msg + 8, 16); + #endif + + if (verbose > 1) + printbuf(session->v2_data.console_rand, 16, + ">> Console generated random number"); + + + /* + * Requested maximum privilege level. + */ + msg[24] = session->privlvl | session->v2_data.lookupbit; + session->v2_data.requested_role = msg[24]; + msg[25] = 0; /* reserved */ + msg[26] = 0; /* reserved */ + + + /* Username specification */ + msg[27] = strlen((const char *)session->username); + if (msg[27] > IPMI_MAX_USER_NAME_LENGTH) + { + lprintf(LOG_ERR, "ERROR: user name too long. " + "(Exceeds %d characters)", + IPMI_MAX_USER_NAME_LENGTH); + free(msg); + msg = NULL; + return 1; + } + memcpy(msg + 28, session->username, msg[27]); + + v2_payload.payload_type = IPMI_PAYLOAD_TYPE_RAKP_1; + v2_payload.payload_length = + IPMI_RAKP1_MESSAGE_SIZE - (16 - msg[27]); + v2_payload.payload.rakp_1_message.message = msg; + + rsp = ipmi_lanplus_send_payload(intf, &v2_payload); + + free(msg); + msg = NULL; + + if (rsp == NULL) + { + lprintf(LOG_WARNING, "> Error: no response from RAKP 1 message"); + return 2; + } + + session->v2_data.session_state = LANPLUS_STATE_RAKP_2_RECEIVED; + + if (verbose) + lanplus_dump_rakp2_message(rsp, session->v2_data.auth_alg); + + + + if (rsp->payload.rakp2_message.rakp_return_code != IPMI_RAKP_STATUS_NO_ERRORS) + { + lprintf(LOG_INFO, "RAKP 2 message indicates an error : %s", + val2str(rsp->payload.rakp2_message.rakp_return_code, + ipmi_rakp_return_codes)); + rc = 1; + } + + else + { + memcpy(session->v2_data.bmc_rand, rsp->payload.rakp2_message.bmc_rand, 16); + memcpy(session->v2_data.bmc_guid, rsp->payload.rakp2_message.bmc_guid, 16); + + if (verbose > 2) + printbuf(session->v2_data.bmc_rand, 16, "bmc_rand"); + + /* + * It is at this point that we have to decode the random number and determine + * whether the BMC has authenticated. + */ + if (! lanplus_rakp2_hmac_matches(session, + rsp->payload.rakp2_message.key_exchange_auth_code, + intf)) + { + /* Error */ + lprintf(LOG_INFO, "> RAKP 2 HMAC is invalid"); + session->v2_data.rakp2_return_code = IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE; + rc = 1; + } + else + { + /* Success */ + session->v2_data.rakp2_return_code = IPMI_RAKP_STATUS_NO_ERRORS; + } + } + + return rc; +} + + + +/* + * ipmi_lanplus_rakp3 + * + * Build and send the RAKP 3 message as part of the IPMI v2 / RMCP+ session + * negotiation protocol. We also read and validate the RAKP 4 message received + * from the BMC, here. See section 13.20 of the IPMI v2 specification for + * details. + * + * If the RAKP 2 return code is not IPMI_RAKP_STATUS_NO_ERRORS, we will + * exit with an error code immediately after sendint the RAKP 3 message. + * + * param intf is the intf that holds all the state we are concerned with + * + * returns 0 on success + * 1 on failure + */ +static int +ipmi_lanplus_rakp3(struct ipmi_intf * intf) +{ + struct ipmi_v2_payload v2_payload; + struct ipmi_session * session = intf->session; + uint8_t * msg; + struct ipmi_rs * rsp; + + assert(session->v2_data.session_state == LANPLUS_STATE_RAKP_2_RECEIVED); + + /* + * Build a RAKP 3 message + */ + msg = (uint8_t*)malloc(IPMI_RAKP3_MESSAGE_MAX_SIZE); + if (msg == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + memset(msg, 0, IPMI_RAKP3_MESSAGE_MAX_SIZE); + + + msg[0] = 0; /* Message tag */ + msg[1] = session->v2_data.rakp2_return_code; + + msg[2] = 0; /* reserved */ + msg[3] = 0; /* reserved */ + + /* BMC session ID */ + msg[4] = session->v2_data.bmc_id & 0xff; + msg[5] = (session->v2_data.bmc_id >> 8) & 0xff; + msg[6] = (session->v2_data.bmc_id >> 16) & 0xff; + msg[7] = (session->v2_data.bmc_id >> 24) & 0xff; + + v2_payload.payload_type = IPMI_PAYLOAD_TYPE_RAKP_3; + v2_payload.payload_length = 8; + v2_payload.payload.rakp_3_message.message = msg; + + /* + * If the rakp2 return code indicates and error, we don't have to + * generate an authcode or session integrity key. In that case, we + * are simply sending a RAKP 3 message to indicate to the BMC that the + * RAKP 2 message caused an error. + */ + if (session->v2_data.rakp2_return_code == IPMI_RAKP_STATUS_NO_ERRORS) + { + uint32_t auth_length; + + if (lanplus_generate_rakp3_authcode(msg + 8, session, &auth_length, intf)) + { + /* Error */ + lprintf(LOG_INFO, "> Error generating RAKP 3 authcode"); + free(msg); + msg = NULL; + return 1; + } + else + { + /* Success */ + v2_payload.payload_length += auth_length; + } + + /* Generate our Session Integrity Key, K1, and K2 */ + if (lanplus_generate_sik(session, intf)) + { + /* Error */ + lprintf(LOG_INFO, "> Error generating session integrity key"); + free(msg); + msg = NULL; + return 1; + } + else if (lanplus_generate_k1(session)) + { + /* Error */ + lprintf(LOG_INFO, "> Error generating K1 key"); + free(msg); + msg = NULL; + return 1; + } + else if (lanplus_generate_k2(session)) + { + /* Error */ + lprintf(LOG_INFO, "> Error generating K1 key"); + free(msg); + msg = NULL; + return 1; + } + } + + + rsp = ipmi_lanplus_send_payload(intf, &v2_payload); + + free(msg); + msg = NULL; + + if (session->v2_data.rakp2_return_code != IPMI_RAKP_STATUS_NO_ERRORS) + { + /* + * If the previous RAKP 2 message received was deemed erroneous, + * we have nothing else to do here. We only sent the RAKP 3 message + * to indicate to the BMC that the RAKP 2 message failed. + */ + return 1; + } + else if (rsp == NULL) + { + lprintf(LOG_WARNING, "> Error: no response from RAKP 3 message"); + return 2; + } + + + /* + * We have a RAKP 4 message to chew on. + */ + if (verbose) + lanplus_dump_rakp4_message(rsp, session->v2_data.auth_alg); + + + if (rsp->payload.open_session_response.rakp_return_code != IPMI_RAKP_STATUS_NO_ERRORS) + { + lprintf(LOG_INFO, "RAKP 4 message indicates an error : %s", + val2str(rsp->payload.rakp4_message.rakp_return_code, + ipmi_rakp_return_codes)); + return 1; + } + + else + { + /* Validate the authcode */ + if (lanplus_rakp4_hmac_matches(session, + rsp->payload.rakp4_message.integrity_check_value, + intf)) + { + /* Success */ + session->v2_data.session_state = LANPLUS_STATE_ACTIVE; + } + else + { + /* Error */ + lprintf(LOG_INFO, "> RAKP 4 message has invalid integrity check value"); + return 1; + } + } + + intf->abort = 0; + return 0; +} + + + +/** + * ipmi_lan_close + */ +void +ipmi_lanplus_close(struct ipmi_intf * intf) +{ + if (!intf->abort) + ipmi_close_session_cmd(intf); + + if (intf->fd >= 0) + close(intf->fd); + + ipmi_req_clear_entries(); + + if (intf->session) { + free(intf->session); + intf->session = NULL; + } + + intf->session = NULL; + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; + intf = NULL; +} + + + +static int +ipmi_set_session_privlvl_cmd(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req; + uint8_t backupBridgePossible; + uint8_t privlvl = intf->session->privlvl; + + if (privlvl <= IPMI_SESSION_PRIV_USER) + return 0; /* no need to set higher */ + + backupBridgePossible = bridgePossible; + + bridgePossible = 0; + + memset(&req, 0, sizeof(req)); + req.msg.netfn = IPMI_NETFN_APP; + req.msg.cmd = 0x3b; + req.msg.data = &privlvl; + req.msg.data_len = 1; + + rsp = intf->sendrecv(intf, &req); + if (rsp == NULL) { + lprintf(LOG_ERR, "Set Session Privilege Level to %s failed", + val2str(privlvl, ipmi_privlvl_vals)); + bridgePossible = backupBridgePossible; + return -1; + } + if (verbose > 2) + printbuf(rsp->data, rsp->data_len, "set_session_privlvl"); + + if (rsp->ccode > 0) { + lprintf(LOG_ERR, "Set Session Privilege Level to %s failed: %s", + val2str(privlvl, ipmi_privlvl_vals), + val2str(rsp->ccode, completion_code_vals)); + bridgePossible = backupBridgePossible; + return -1; + } + + lprintf(LOG_DEBUG, "Set Session Privilege Level to %s\n", + val2str(rsp->data[0], ipmi_privlvl_vals)); + + bridgePossible = backupBridgePossible; + + return 0; +} + +/** + * ipmi_lanplus_open + */ +int +ipmi_lanplus_open(struct ipmi_intf * intf) +{ + int rc; + int retry; + struct get_channel_auth_cap_rsp auth_cap; + struct ipmi_session *session; + + if (!intf || !intf->session) + return -1; + session = intf->session; + + + if (!session->port) + session->port = IPMI_LANPLUS_PORT; + if (!session->privlvl) + session->privlvl = IPMI_SESSION_PRIV_ADMIN; + if (!session->timeout) + session->timeout = IPMI_LAN_TIMEOUT; + if (!session->retry) + session->retry = IPMI_LAN_RETRY; + + if (session->hostname == NULL || strlen((const char *)session->hostname) == 0) { + lprintf(LOG_ERR, "No hostname specified!"); + return -1; + } + + intf->abort = 1; + + + /* Setup our lanplus session state */ + session->v2_data.auth_alg = IPMI_AUTH_RAKP_NONE; + session->v2_data.crypt_alg = IPMI_CRYPT_NONE; + session->v2_data.console_id = 0x00; + session->v2_data.bmc_id = 0x00; + session->sol_data.sequence_number = 1; + //session->sol_data.last_received_sequence_number = 0; + //session->sol_data.last_received_byte_count = 0; + memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE); + + /* Kg is set in ipmi_intf */ + //memset(session->v2_data.kg, 0, IPMI_KG_BUFFER_SIZE); + + if (ipmi_intf_socket_connect (intf) == -1) { + lprintf(LOG_ERR, "Could not open socket!"); + return -1; + } + + if (intf->fd < 0) { + lperror(LOG_ERR, "Connect to %s failed", + session->hostname); + intf->close(intf); + return -1; + } + + intf->opened = 1; + + /* + * + * Make sure the BMC supports IPMI v2 / RMCP+ + */ + if (!ipmi_oem_active(intf, "i82571spt") && + ipmi_get_auth_capabilities_cmd(intf, &auth_cap)) { + lprintf(LOG_INFO, "Error issuing Get Channel " + "Authentication Capabilies request"); + goto fail; + } + + if (!ipmi_oem_active(intf, "i82571spt") && ! auth_cap.v20_data_available) + { + lprintf(LOG_INFO, "This BMC does not support IPMI v2 / RMCP+"); + goto fail; + } + + /* + * If the open/rakp1/rakp3 sequence encounters a timeout, the whole sequence + * needs to restart. The individual messages are not individually retryable, + * as the session state is advancing. + */ + for (retry = 0; retry < IPMI_LAN_RETRY; retry++) { + session->v2_data.session_state = LANPLUS_STATE_PRESESSION; + /* + * Open session + */ + if ((rc = ipmi_lanplus_open_session(intf)) == 1) { + intf->close(intf); + goto fail; + } + if (rc == 2) { + lprintf(LOG_DEBUG, "Retry lanplus open session, %d", retry); + continue; + } + /* + * RAKP 1 + */ + if ((rc = ipmi_lanplus_rakp1(intf)) == 1) { + intf->close(intf); + goto fail; + } + if (rc == 2) { + lprintf(LOG_DEBUG, "Retry lanplus rakp1, %d", retry); + continue; + } + /* + * RAKP 3 + */ + if ((rc = ipmi_lanplus_rakp3(intf)) == 1) { + intf->close(intf); + goto fail; + } + if (rc == 0) break; + lprintf(LOG_DEBUG,"Retry lanplus rakp3, %d", retry); + } + + lprintf(LOG_DEBUG, "IPMIv2 / RMCP+ SESSION OPENED SUCCESSFULLY\n"); + + if (!ipmi_oem_active(intf, "i82571spt")) { + rc = ipmi_set_session_privlvl_cmd(intf); + if (rc < 0) { + intf->close(intf); + goto fail; + } + } + intf->manufacturer_id = ipmi_get_oem(intf); + bridgePossible = 1; + + /* automatically detect interface request and response sizes */ + hpm2_detect_max_payload_size(intf); + + return intf->fd; + + fail: + lprintf(LOG_ERR, "Error: Unable to establish IPMI v2 / RMCP+ session"); + intf->opened = 0; + return -1; +} + + + +void test_crypt1(void) +{ + uint8_t key[] = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}; + + uint16_t bytes_encrypted; + uint16_t bytes_decrypted; + uint8_t decrypt_buffer[1000]; + uint8_t encrypt_buffer[1000]; + + uint8_t data[] = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, + 0x11, 0x12}; + + printbuf(data, sizeof(data), "original data"); + + if (lanplus_encrypt_payload(IPMI_CRYPT_AES_CBC_128, + key, + data, + sizeof(data), + encrypt_buffer, + &bytes_encrypted)) + { + lprintf(LOG_ERR, "Encrypt test failed"); + assert(0); + } + printbuf(encrypt_buffer, bytes_encrypted, "encrypted payload"); + + + if (lanplus_decrypt_payload(IPMI_CRYPT_AES_CBC_128, + key, + encrypt_buffer, + bytes_encrypted, + decrypt_buffer, + &bytes_decrypted)) + { + lprintf(LOG_ERR, "Decrypt test failed\n"); + assert(0); + } + printbuf(decrypt_buffer, bytes_decrypted, "decrypted payload"); + + lprintf(LOG_DEBUG, "\nDone testing the encrypt/decyrpt methods!\n"); + exit(0); +} + + + +void test_crypt2(void) +{ + uint8_t key[] = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}; + uint8_t iv[] = + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}; + uint8_t data[8] = "12345678"; + + uint8_t encrypt_buffer[1000]; + uint8_t decrypt_buffer[1000]; + uint32_t bytes_encrypted; + uint32_t bytes_decrypted; + + printbuf((const uint8_t *)data, strlen((const char *)data), "input data"); + + lanplus_encrypt_aes_cbc_128(iv, + key, + data, + strlen((const char *)data), + encrypt_buffer, + &bytes_encrypted); + printbuf((const uint8_t *)encrypt_buffer, bytes_encrypted, "encrypt_buffer"); + + lanplus_decrypt_aes_cbc_128(iv, + key, + encrypt_buffer, + bytes_encrypted, + decrypt_buffer, + &bytes_decrypted); + printbuf((const uint8_t *)decrypt_buffer, bytes_decrypted, "decrypt_buffer"); + + lprintf(LOG_INFO, "\nDone testing the encrypt/decyrpt methods!\n"); + exit(0); +} + + +/** + * send a get device id command to keep session active + */ +static int +ipmi_lanplus_keepalive(struct ipmi_intf * intf) +{ + struct ipmi_rs * rsp; + struct ipmi_rq req = { msg: { + netfn: IPMI_NETFN_APP, + cmd: 1, + }}; + + if (!intf->opened) + return 0; + + rsp = intf->sendrecv(intf, &req); + while (rsp != NULL && is_sol_packet(rsp)) { + /* rsp was SOL data instead of our answer */ + /* since it didn't go through the sol recv, do sol recv stuff here */ + ack_sol_packet(intf, rsp); + check_sol_packet_for_new_data(intf, rsp); + if (rsp->data_len) + intf->session->sol_data.sol_input_handler(rsp); + rsp = ipmi_lan_poll_recv(intf); + if (rsp == NULL) /* the get device id answer never got back, but retry mechanism was bypassed by SOL data */ + return 0; /* so get device id command never returned, the connection is still alive */ + } + + if (rsp == NULL) + return -1; + if (rsp->ccode > 0) + return -1; + + return 0; +} + + +/** + * ipmi_lanplus_setup + */ +static int ipmi_lanplus_setup(struct ipmi_intf * intf) +{ + //test_crypt1(); + assert("ipmi_lanplus_setup"); + + if (lanplus_seed_prng(16)) + return -1; + + intf->session = malloc(sizeof(struct ipmi_session)); + if (intf->session == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + memset(intf->session, 0, sizeof(struct ipmi_session)); + + /* setup default LAN maximum request and response sizes */ + intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE; + intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE; + + return 0; +} + +static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size) +{ + if (intf->session->cipher_suite_id == 3) { + /* + * encrypted payload can only be multiple of 16 bytes + */ + size &= ~15; + + /* + * decrement payload size on confidentiality header size + * plus minimal confidentiality trailer size + */ + size -= (16 + 1); + } + + intf->max_request_data_size = size; +} + +static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size) +{ + if (intf->session->cipher_suite_id == 3) { + /* + * encrypted payload can only be multiple of 16 bytes + */ + size &= ~15; + + /* + * decrement payload size on confidentiality header size + * plus minimal confidentiality trailer size + */ + size -= (16 + 1); + } + + intf->max_response_data_size = size; +} diff --git a/src/plugins/lanplus/lanplus.h b/src/plugins/lanplus/lanplus.h new file mode 100644 index 0000000..4b6ae1e --- /dev/null +++ b/src/plugins/lanplus/lanplus.h @@ -0,0 +1,126 @@ +/* + * 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_LANPLUS_H +#define IPMI_LANPLUS_H + +#include <ipmitool/ipmi.h> + +#define IPMI_LANPLUS_PORT 0x26f + +/* + * RAKP return codes. These values come from table 13-15 of the IPMI v2 + * specification. + */ +#define IPMI_RAKP_STATUS_NO_ERRORS 0x00 +#define IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_SESSION 0x01 +#define IPMI_RAKP_STATUS_INVALID_SESSION_ID 0x02 +#define IPMI_RAKP_STATUS_INVALID_PAYLOAD_TYPE 0x03 +#define IPMI_RAKP_STATUS_INVALID_AUTHENTICATION_ALGORITHM 0x04 +#define IPMI_RAKP_STATUS_INVALID_INTEGRITTY_ALGORITHM 0x05 +#define IPMI_RAKP_STATUS_NO_MATCHING_AUTHENTICATION_PAYLOAD 0x06 +#define IPMI_RAKP_STATUS_NO_MATCHING_INTEGRITY_PAYLOAD 0x07 +#define IPMI_RAKP_STATUS_INACTIVE_SESSION_ID 0x08 +#define IPMI_RAKP_STATUS_INVALID_ROLE 0x09 +#define IPMI_RAKP_STATUS_UNAUTHORIZED_ROLE_REQUESTED 0x0A +#define IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_ROLE 0x0B +#define IPMI_RAKP_STATUS_INVALID_NAME_LENGTH 0x0C +#define IPMI_RAKP_STATUS_UNAUTHORIZED_NAME 0x0D +#define IPMI_RAKP_STATUS_UNAUTHORIZED_GUID 0x0E +#define IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE 0x0F +#define IPMI_RAKP_STATUS_INVALID_CONFIDENTIALITY_ALGORITHM 0x10 +#define IPMI_RAKP_STATUS_NO_CIPHER_SUITE_MATCH 0x11 +#define IPMI_RAKP_STATUS_ILLEGAL_PARAMTER 0x12 + + +#define IPMI_LAN_CHANNEL_1 0x07 +#define IPMI_LAN_CHANNEL_2 0x06 +#define IPMI_LAN_CHANNEL_E 0x0e + +#define IPMI_LAN_TIMEOUT 1 +#define IPMI_LAN_RETRY 4 + +#define IPMI_PRIV_CALLBACK 1 +#define IPMI_PRIV_USER 2 +#define IPMI_PRIV_OPERATOR 3 +#define IPMI_PRIV_ADMIN 4 +#define IPMI_PRIV_OEM 5 + + +#define IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE 0x10 + + +/* Session message offsets, from table 13-8 of the v2 specification */ +#define IPMI_LANPLUS_OFFSET_AUTHTYPE 0x04 +#define IPMI_LANPLUS_OFFSET_PAYLOAD_TYPE 0x05 +#define IPMI_LANPLUS_OFFSET_SESSION_ID 0x06 +#define IPMI_LANPLUS_OFFSET_SEQUENCE_NUM 0x0A +#define IPMI_LANPLUS_OFFSET_PAYLOAD_SIZE 0x0E +#define IPMI_LANPLUS_OFFSET_PAYLOAD 0x10 + + +#define IPMI_GET_CHANNEL_AUTH_CAP 0x38 + +/* + * TODO: these are wild guesses and should be checked + */ +#define IPMI_MAX_CONF_HEADER_SIZE 0x20 +#define IPMI_MAX_PAYLOAD_SIZE 0xFFFF /* Includes confidentiality header/trailer */ +#define IPMI_MAX_CONF_TRAILER_SIZE 0x20 +#define IPMI_MAX_INTEGRITY_PAD_SIZE 0x20 +#define IPMI_MAX_AUTH_CODE_SIZE 0x20 + +#define IPMI_REQUEST_MESSAGE_SIZE 0x07 +#define IPMI_MAX_MAC_SIZE 0x14 /* The largest mac we ever expect to generate */ +#define IPMI_SHA1_AUTHCODE_SIZE 0x0C + +/* + *This is accurate, as long as we're only passing 1 auth algorithm, + * one integrity algorithm, and 1 encyrption alogrithm + */ +#define IPMI_OPEN_SESSION_REQUEST_SIZE 32 +#define IPMI_RAKP1_MESSAGE_SIZE 44 +#define IPMI_RAKP3_MESSAGE_MAX_SIZE 28 + +#define IPMI_MAX_USER_NAME_LENGTH 16 + +extern const struct valstr ipmi_privlvl_vals[]; +extern const struct valstr ipmi_authtype_vals[]; + +extern struct ipmi_intf ipmi_lanplus_intf; + +struct ipmi_rs * ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req); +int ipmi_lanplus_open(struct ipmi_intf * intf); +void ipmi_lanplus_close(struct ipmi_intf * intf); +int ipmiv2_lan_ping(struct ipmi_intf * intf); + +#endif /*IPMI_LAN_H*/ diff --git a/src/plugins/lanplus/lanplus_crypt.c b/src/plugins/lanplus/lanplus_crypt.c new file mode 100644 index 0000000..54fd5cb --- /dev/null +++ b/src/plugins/lanplus/lanplus_crypt.c @@ -0,0 +1,934 @@ +/* + * 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 <assert.h> +#include <string.h> +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif +#include <ipmitool/bswap.h> +#include <ipmitool/log.h> +#include "lanplus.h" +#include "lanplus_crypt.h" +#include "lanplus_crypt_impl.h" + + + +/* + * lanplus_rakp2_hmac_matches + * + * param session holds all the state data that we need to generate the hmac + * param hmac is the HMAC sent by the BMC in the RAKP 2 message + * + * The HMAC was generated [per RFC2404] from : + * + * SIDm - Remote console session ID + * SIDc - BMC session ID + * Rm - Remote console random number + * Rc - BMC random number + * GUIDc - BMC guid + * ROLEm - Requested privilege level (entire byte) + * ULENGTHm - Username length + * <UNAMEm> - Username (absent for null user names) + * + * generated by using Kuid. I am aware that the subscripts on the values + * look backwards, but that's the way they are written in the specification. + * + * If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success. + * + * return 0 on success (the authcode matches) + * 1 on failure (the authcode does not match) + */ +int +lanplus_rakp2_hmac_matches(const struct ipmi_session * session, + const uint8_t * bmc_mac, struct ipmi_intf * intf) +{ + uint8_t * buffer; + int bufferLength, i; + uint8_t mac[20]; + uint32_t macLength; + + uint32_t SIDm_lsbf, SIDc_lsbf; + + + if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) + return 1; + + /* We don't yet support other algorithms */ + assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + + + bufferLength = + 4 + /* SIDm */ + 4 + /* SIDc */ + 16 + /* Rm */ + 16 + /* Rc */ + 16 + /* GUIDc */ + 1 + /* ROLEm */ + 1 + /* ULENGTHm */ + strlen((const char *)session->username); /* optional */ + + buffer = malloc(bufferLength); + if (buffer == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + + /* + * Fill the buffer. I'm assuming that we're using the LSBF representation of the + * multibyte numbers in use. + */ + + /* SIDm */ + SIDm_lsbf = session->v2_data.console_id; + #if WORDS_BIGENDIAN + SIDm_lsbf = BSWAP_32(SIDm_lsbf); + #endif + + memcpy(buffer, &SIDm_lsbf, 4); + + /* SIDc */ + SIDc_lsbf = session->v2_data.bmc_id; + #if WORDS_BIGENDIAN + SIDc_lsbf = BSWAP_32(SIDc_lsbf); + #endif + memcpy(buffer + 4, &SIDc_lsbf, 4); + + /* Rm */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + buffer[8 + i] = session->v2_data.console_rand[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + buffer[8 + i] = session->v2_data.console_rand[i]; + #endif + + /* Rc */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + buffer[24 + i] = session->v2_data.bmc_rand[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + buffer[24 + i] = session->v2_data.bmc_rand[i]; + #endif + + /* GUIDc */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + buffer[40 + i] = session->v2_data.bmc_guid[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + buffer[40 + i] = session->v2_data.bmc_guid[i]; + #endif + + /* ROLEm */ + buffer[56] = session->v2_data.requested_role; + + if (ipmi_oem_active(intf, "i82571spt")) { + /* + * The HMAC calculation code in the Intel 82571 GbE + * skips this bit! Looks like a GbE bug, but we need + * to work around it here anyway... + */ + buffer[56] &= ~0x10; + } + + /* ULENGTHm */ + buffer[57] = strlen((const char *)session->username); + + /* UserName [optional] */ + for (i = 0; i < buffer[57]; ++i) + buffer[58 + i] = session->username[i]; + + if (verbose > 2) + { + printbuf((const uint8_t *)buffer, bufferLength, ">> rakp2 mac input buffer"); + printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp2 mac key"); + } + + /* + * The buffer is complete. Let's hash. + */ + lanplus_HMAC(session->v2_data.auth_alg, + session->authcode, + IPMI_AUTHCODE_BUFFER_SIZE, + buffer, + bufferLength, + mac, + &macLength); + + free(buffer); + buffer = NULL; + + + if (verbose > 2) + { + printbuf(mac, macLength, ">> rakp2 mac as computed by the remote console"); + } + + return (memcmp(bmc_mac, mac, macLength) == 0); +} + + + +/* + * lanplus_rakp4_hmac_matches + * + * param session holds all the state data that we need to generate the hmac + * param hmac is the HMAC sent by the BMC in the RAKP 4 message + * + * The HMAC was generated [per RFC2404] from : + * + * Rm - Remote console random number + * SIDc - BMC session ID + * GUIDc - BMC guid + * + * generated by using SIK (the session integrity key). I am aware that the + * subscripts on the values look backwards, but that's the way they are + * written in the specification. + * + * If the authentication algorithm is IPMI_AUTH_RAKP_NONE, we return success. + * + * return 1 on success (the authcode matches) + * 0 on failure (the authcode does not match) + * + */ +int +lanplus_rakp4_hmac_matches(const struct ipmi_session * session, + const uint8_t * bmc_mac, struct ipmi_intf * intf) +{ + uint8_t * buffer; + int bufferLength, i; + uint8_t mac[20]; + uint32_t macLength; + uint32_t SIDc_lsbf; + + if (ipmi_oem_active(intf, "intelplus")){ + /* Intel BMC responds with the integrity Algorithm in RAKP4 */ + if (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE) + return 1; + + /* We don't yet support other algorithms */ + assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96); + } else { + if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) + return 1; + + /* We don't yet support other algorithms */ + assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + } + + bufferLength = + 16 + /* Rm */ + 4 + /* SIDc */ + 16; /* GUIDc */ + + buffer = (uint8_t *)malloc(bufferLength); + if (buffer == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + + /* + * Fill the buffer. I'm assuming that we're using the LSBF representation of the + * multibyte numbers in use. + */ + + /* Rm */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + buffer[i] = session->v2_data.console_rand[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + buffer[i] = session->v2_data.console_rand[i]; + #endif + + + /* SIDc */ + SIDc_lsbf = session->v2_data.bmc_id; + #if WORDS_BIGENDIAN + SIDc_lsbf = BSWAP_32(SIDc_lsbf); + #endif + memcpy(buffer + 16, &SIDc_lsbf, 4); + + + /* GUIDc */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + buffer[i + 20] = session->v2_data.bmc_guid[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + buffer[i + 20] = session->v2_data.bmc_guid[i]; + #endif + + + if (verbose > 2) + { + printbuf((const uint8_t *)buffer, bufferLength, ">> rakp4 mac input buffer"); + printbuf(session->v2_data.sik, 20l, ">> rakp4 mac key (sik)"); + } + + + /* + * The buffer is complete. Let's hash. + */ + lanplus_HMAC((ipmi_oem_active(intf, "intelplus")) + ? session->v2_data.integrity_alg + : session->v2_data.auth_alg , + session->v2_data.sik, + IPMI_SIK_BUFFER_SIZE, + buffer, + bufferLength, + mac, + &macLength); + + if (verbose > 2) + { + printbuf(bmc_mac, macLength, ">> rakp4 mac as computed by the BMC"); + printbuf(mac, macLength, ">> rakp4 mac as computed by the remote console"); + } + + + + free(buffer); + buffer = NULL; + assert(macLength == 20); + return (memcmp(bmc_mac, mac, 12) == 0); +} + + + +/* + * lanplus_generate_rakp3_auth_code + * + * This auth code is an HMAC generated with : + * + * Rc - BMC random number + * SIDm - Console session ID + * ROLEm - Requested privilege level (entire byte) + * ULENGTHm - Username length + * <USERNAME> - Usename (absent for null usernames) + * + * The key used to generated the MAC is Kuid + * + * I am aware that the subscripts look backwards, but that is the way they are + * written in the spec. + * + * param output_buffer [out] will hold the generated MAC + * param session [in] holds all the state data we need to generate the auth code + * param mac_length [out] will be set to the length of the auth code + * + * returns 0 on success + * 1 on failure + */ +int +lanplus_generate_rakp3_authcode(uint8_t * output_buffer, + const struct ipmi_session * session, + uint32_t * mac_length, struct ipmi_intf * intf) +{ + int ret = 0; + int input_buffer_length, i; + uint8_t * input_buffer; + uint32_t SIDm_lsbf; + + + if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) + { + *mac_length = 0; + return 0; + } + + /* We don't yet support other algorithms */ + assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + + input_buffer_length = + 16 + /* Rc */ + 4 + /* SIDm */ + 1 + /* ROLEm */ + 1 + /* ULENGTHm */ + strlen((const char *)session->username); + + input_buffer = malloc(input_buffer_length); + if (input_buffer == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + + /* + * Fill the buffer. I'm assuming that we're using the LSBF representation of the + * multibyte numbers in use. + */ + + /* Rc */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + input_buffer[i] = session->v2_data.bmc_rand[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + input_buffer[i] = session->v2_data.bmc_rand[i]; + #endif + + /* SIDm */ + SIDm_lsbf = session->v2_data.console_id; + #if WORDS_BIGENDIAN + SIDm_lsbf = BSWAP_32(SIDm_lsbf); + #endif + memcpy(input_buffer + 16, &SIDm_lsbf, 4); + + /* ROLEm */ + if (ipmi_oem_active(intf, "intelplus") || ipmi_oem_active(intf, "i82571spt")) + input_buffer[20] = session->privlvl; + else + input_buffer[20] = session->v2_data.requested_role; + + /* ULENGTHm */ + input_buffer[21] = strlen((const char *)session->username); + + /* USERNAME */ + for (i = 0; i < input_buffer[21]; ++i) + input_buffer[22 + i] = session->username[i]; + + if (verbose > 2) + { + printbuf((const uint8_t *)input_buffer, input_buffer_length, ">> rakp3 mac input buffer"); + printbuf((const uint8_t *)session->authcode, IPMI_AUTHCODE_BUFFER_SIZE, ">> rakp3 mac key"); + } + + lanplus_HMAC(session->v2_data.auth_alg, + session->authcode, + IPMI_AUTHCODE_BUFFER_SIZE, + input_buffer, + input_buffer_length, + output_buffer, + mac_length); + + if (verbose > 2) + printbuf((const uint8_t *)output_buffer, *mac_length, "generated rakp3 mac"); + + + free(input_buffer); + input_buffer = NULL; + + return ret; +} + + + +/* + * lanplus_generate_sik + * + * Generate the session integrity key (SIK) used for integrity checking + * during the IPMI v2 / RMCP+ session + * + * This session integrity key is a HMAC generated with : + * + * Rm - Console generated random number + * Rc - BMC generated random number + * ROLEm - Requested privilege level (entire byte) + * ULENGTHm - Username length + * <USERNAME> - Usename (absent for null usernames) + * + * The key used to generated the SIK is Kg if Kg is not null (two-key logins are + * enabled). Otherwise Kuid (the user authcode) is used as the key to genereate + * the SIK. + * + * I am aware that the subscripts look backwards, but that is the way they are + * written in the spec. + * + * param session [in/out] contains our input and output fields. + * + * returns 0 on success + * 1 on failure + */ +int +lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf) +{ + uint8_t * input_buffer; + int input_buffer_length, i; + uint8_t * input_key; + uint32_t mac_length; + + + memset(session->v2_data.sik, 0, IPMI_SIK_BUFFER_SIZE); + + if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) + return 0; + + /* We don't yet support other algorithms */ + assert(session->v2_data.auth_alg == IPMI_AUTH_RAKP_HMAC_SHA1); + + input_buffer_length = + 16 + /* Rm */ + 16 + /* Rc */ + 1 + /* ROLEm */ + 1 + /* ULENGTHm */ + strlen((const char *)session->username); + + input_buffer = malloc(input_buffer_length); + if (input_buffer == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + + /* + * Fill the buffer. I'm assuming that we're using the LSBF representation of the + * multibyte numbers in use. + */ + + /* Rm */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + input_buffer[i] = session->v2_data.console_rand[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + input_buffer[i] = session->v2_data.console_rand[i]; + #endif + + + /* Rc */ + #if WORDS_BIGENDIAN + for (i = 0; i < 16; ++i) + input_buffer[16 + i] = session->v2_data.bmc_rand[16 - 1 - i]; + #else + for (i = 0; i < 16; ++i) + input_buffer[16 + i] = session->v2_data.bmc_rand[i]; + #endif + + /* ROLEm */ + input_buffer[32] = session->v2_data.requested_role; + + if (ipmi_oem_active(intf, "i82571spt")) { + /* + * The HMAC calculation code in the Intel 82571 GbE + * skips this bit! Looks like a GbE bug, but we need + * to work around it here anyway... + */ + input_buffer[32] &= ~0x10; + } + + /* ULENGTHm */ + input_buffer[33] = strlen((const char *)session->username); + + /* USERNAME */ + for (i = 0; i < input_buffer[33]; ++i) + input_buffer[34 + i] = session->username[i]; + + if (session->v2_data.kg[0]) + { + /* We will be hashing with Kg */ + /* + * Section 13.31 of the IPMI v2 spec describes the SIK creation + * using Kg. It specifies that Kg should not be truncated. + * Kg is set in ipmi_intf. + */ + input_key = session->v2_data.kg; + } + else + { + /* We will be hashing with Kuid */ + input_key = session->authcode; + } + + + if (verbose >= 2) + printbuf((const uint8_t *)input_buffer, input_buffer_length, "session integrity key input"); + + lanplus_HMAC(session->v2_data.auth_alg, + input_key, + IPMI_AUTHCODE_BUFFER_SIZE, + input_buffer, + input_buffer_length, + session->v2_data.sik, + &mac_length); + + free(input_buffer); + input_buffer = NULL; + assert(mac_length == 20); + + /* + * The key MAC generated is 20 bytes, but we will only be using the first + * 12 for SHA1 96 + */ + if (verbose >= 2) + printbuf(session->v2_data.sik, 20, "Generated session integrity key"); + + return 0; +} + + + +/* + * lanplus_generate_k1 + * + * Generate K1, the key presumably used to generate integrity authcodes + * + * We use the authentication algorithm to generated the HMAC, using + * the session integrity key (SIK) as our key. + * + * param session [in/out]. + * + * returns 0 on success + * 1 on failure + */ +int +lanplus_generate_k1(struct ipmi_session * session) +{ + uint32_t mac_length; + + uint8_t CONST_1[] = + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; + + if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) + memcpy(session->v2_data.k1, CONST_1, 20); + else + { + lanplus_HMAC(session->v2_data.auth_alg, + session->v2_data.sik, + IPMI_SIK_BUFFER_SIZE, /* SIK length */ + CONST_1, + 20, + session->v2_data.k1, + &mac_length); + assert(mac_length == 20); + } + + if (verbose >= 2) + printbuf(session->v2_data.k1, 20, "Generated K1"); + + return 0; +} + + + +/* + * lanplus_generate_k2 + * + * Generate K2, the key used for RMCP+ AES encryption. + * + * We use the authentication algorithm to generated the HMAC, using + * the session integrity key (SIK) as our key. + * + * param session [in/out]. + * + * returns 0 on success + * 1 on failure + */ +int +lanplus_generate_k2(struct ipmi_session * session) +{ + uint32_t mac_length; + + uint8_t CONST_2[] = + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + + if (session->v2_data.auth_alg == IPMI_AUTH_RAKP_NONE) + memcpy(session->v2_data.k2, CONST_2, 20); + else + { + lanplus_HMAC(session->v2_data.auth_alg, + session->v2_data.sik, + IPMI_SIK_BUFFER_SIZE, /* SIK length */ + CONST_2, + 20, + session->v2_data.k2, + &mac_length); + assert(mac_length == 20); + } + + if (verbose >= 2) + printbuf(session->v2_data.k2, 20, "Generated K2"); + + return 0; +} + + + +/* + * lanplus_encrypt_payload + * + * Perform the appropriate encryption on the input data. Output the encrypted + * data to output, including the required confidentiality header and trailer. + * If the crypt_alg is IPMI_CRYPT_NONE, simply copy the input to the output and + * set bytes_written to input_length. + * + * param crypt_alg specifies the encryption algorithm (from table 13-19 of the + * IPMI v2 spec) + * param key is the used as input to the encryption algorithmf + * param input is the input data to be encrypted + * param input_length is the length of the input data to be encrypted + * param output is the cipher text generated by the encryption process + * param bytes_written is the number of bytes written during the encryption + * process + * + * returns 0 on success + * 1 on failure + */ +int +lanplus_encrypt_payload(uint8_t crypt_alg, + const uint8_t * key, const uint8_t * input, + uint32_t input_length, uint8_t * output, + uint16_t * bytes_written) +{ + uint8_t * padded_input; + uint32_t mod, i, bytes_encrypted; + uint8_t pad_length = 0; + + if (crypt_alg == IPMI_CRYPT_NONE) + { + /* Just copy the input to the output */ + *bytes_written = input_length; + return 0; + } + + /* Currently, we only support AES */ + assert(crypt_alg == IPMI_CRYPT_AES_CBC_128); + assert(input_length <= IPMI_MAX_PAYLOAD_SIZE); + + + /* + * The input to the AES encryption algorithm has to be a multiple of the + * block size (16 bytes). The extra byte we are adding is the pad length + * byte. + */ + mod = (input_length + 1) % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE; + if (mod) + pad_length = IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE - mod; + + padded_input = (uint8_t*)malloc(input_length + pad_length + 1); + if (padded_input == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + memcpy(padded_input, input, input_length); + + /* add the pad */ + for (i = 0; i < pad_length; ++i) + padded_input[input_length + i] = i + 1; + + /* add the pad length */ + padded_input[input_length + pad_length] = pad_length; + + /* Generate an initialization vector, IV, for the encryption process */ + if (lanplus_rand(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE)) + { + lprintf(LOG_ERR, "lanplus_encrypt_payload: Error generating IV"); + if (padded_input != NULL) { + free(padded_input); + padded_input = NULL; + } + return 1; + } + + if (verbose > 2) + printbuf(output, IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, ">> Initialization vector"); + + + + lanplus_encrypt_aes_cbc_128(output, /* IV */ + key, /* K2 */ + padded_input, /* Data to encrypt */ + input_length + pad_length + 1, /* Input length */ + output + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* output */ + &bytes_encrypted); /* bytes written */ + + *bytes_written = + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE + /* IV */ + bytes_encrypted; + + free(padded_input); + padded_input = NULL; + + return 0; +} + + + +/* + * lanplus_has_valid_auth_code + * + * Determine whether the packets authcode field is valid for packet. + * + * We always return success if any of the following are true. + * - this is not an IPMIv2 packet + * - the session is not yet active + * - the packet specifies that it is not authenticated + * - the integrity algorithm agreed upon during session creation is "none" + * + * The authcode is computed using the specified integrity algorithm starting + * with the AuthType / Format field, and ending with the field immediately + * preceeding the authcode itself. + * + * The key key used to generate the authcode MAC is K1. + * + * param rs holds the response structure. + * param session holds our session state, including our chosen algorithm, key, etc. + * + * returns 1 on success (authcode is valid) + * 0 on failure (autchode integrity check failed) + */ +int +lanplus_has_valid_auth_code(struct ipmi_rs * rs, struct ipmi_session * session) +{ + uint8_t * bmc_authcode; + uint8_t generated_authcode[IPMI_MAX_MAC_SIZE]; + uint32_t generated_authcode_length; + + + if ((rs->session.authtype != IPMI_SESSION_AUTHTYPE_RMCP_PLUS) || + (session->v2_data.session_state != LANPLUS_STATE_ACTIVE) || + (! rs->session.bAuthenticated) || + (session->v2_data.integrity_alg == IPMI_INTEGRITY_NONE)) + return 1; + + /* We only support SHA1-96 now */ + assert(session->v2_data.integrity_alg == IPMI_INTEGRITY_HMAC_SHA1_96); + + /* + * For SHA1-96, the authcode will be the last 12 bytes in the packet + */ + bmc_authcode = rs->data + (rs->data_len - IPMI_SHA1_AUTHCODE_SIZE); + + lanplus_HMAC(session->v2_data.integrity_alg, + session->v2_data.k1, + IPMI_AUTHCODE_BUFFER_SIZE, + rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE, + rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE, + generated_authcode, + &generated_authcode_length); + + if (verbose > 3) + { + lprintf(LOG_DEBUG+2, "Validating authcode"); + printbuf(session->v2_data.k1, 20, "K1"); + printbuf(rs->data + IPMI_LANPLUS_OFFSET_AUTHTYPE, + rs->data_len - IPMI_LANPLUS_OFFSET_AUTHTYPE - IPMI_SHA1_AUTHCODE_SIZE, + "Authcode Input Data"); + printbuf(generated_authcode, 12, "Generated authcode"); + printbuf(bmc_authcode, 12, "Expected authcode"); + } + + + assert(generated_authcode_length == 20); + return (memcmp(bmc_authcode, generated_authcode, 12) == 0); +} + + + +/* + * lanplus_decrypt_payload + * + * + * param input points to the beginning of the payload (which will be the IV if + * we are using AES) + * param payload_size [out] will be set to the size of the payload EXCLUDING + * padding + * + * returns 0 on success (we were able to successfully decrypt the packet) + * 1 on failure (we were unable to successfully decrypt the packet) + */ +int +lanplus_decrypt_payload(uint8_t crypt_alg, const uint8_t * key, + const uint8_t * input, uint32_t input_length, + uint8_t * output, uint16_t * payload_size) +{ + uint8_t * decrypted_payload; + uint32_t bytes_decrypted; + + if (crypt_alg == IPMI_CRYPT_NONE) + { + /* We are not encrypted. The paylaod size is is everything. */ + *payload_size = input_length; + memmove(output, input, input_length); + return 0; + } + + /* We only support AES */ + assert(crypt_alg == IPMI_CRYPT_AES_CBC_128); + + decrypted_payload = (uint8_t*)malloc(input_length); + if (decrypted_payload == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return 1; + } + + + lanplus_decrypt_aes_cbc_128(input, /* IV */ + key, /* Key */ + input + + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* Data to decrypt */ + input_length - + IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE, /* Input length */ + decrypted_payload, /* output */ + &bytes_decrypted); /* bytes written */ + + if (bytes_decrypted != 0) + { + /* Success */ + uint8_t conf_pad_length; + int i; + + memmove(output, + decrypted_payload, + bytes_decrypted); + + /* + * We have to determine the payload size, by substracting the padding, etc. + * The last byte of the decrypted payload is the confidentiality pad length. + */ + conf_pad_length = decrypted_payload[bytes_decrypted - 1]; + *payload_size = bytes_decrypted - conf_pad_length - 1; + + /* + * Extra test to make sure that the padding looks like it should (should start + * with 0x01, 0x02, 0x03, etc... + */ + for (i = 0; i < conf_pad_length; ++i) + { + if (decrypted_payload[*payload_size + i] != (i + 1)) + { + lprintf(LOG_ERR, "Malformed payload padding"); + assert(0); + } + } + } + else + { + lprintf(LOG_ERR, "ERROR: lanplus_decrypt_aes_cbc_128 decryptd 0 bytes"); + assert(0); + } + + free(decrypted_payload); + decrypted_payload = NULL; + return (bytes_decrypted == 0); +} diff --git a/src/plugins/lanplus/lanplus_crypt.h b/src/plugins/lanplus/lanplus_crypt.h new file mode 100644 index 0000000..d69cc9b --- /dev/null +++ b/src/plugins/lanplus/lanplus_crypt.h @@ -0,0 +1,75 @@ +/* + * 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_LANPLUS_CRYPT_H +#define IPMI_LANPLUS_CRYPT_H + +#include <ipmitool/ipmi_intf.h> + +/* + * See the implementation file for documentation + * ipmi_intf can be used for oem specific implementations + * e.g. if (ipmi_oem_active(intf, "OEM_XYZ")) + */ + +int lanplus_rakp2_hmac_matches(const struct ipmi_session * session, + const uint8_t * hmac, + struct ipmi_intf * intf); +int lanplus_rakp4_hmac_matches(const struct ipmi_session * session, + const uint8_t * hmac, + struct ipmi_intf * intf); +int lanplus_generate_rakp3_authcode(uint8_t * buffer, + const struct ipmi_session * session, + uint32_t * auth_length, + struct ipmi_intf * intf); +int lanplus_generate_sik(struct ipmi_session * session, struct ipmi_intf * intf); +int lanplus_generate_k1(struct ipmi_session * session); +int lanplus_generate_k2(struct ipmi_session * session); +int lanplus_encrypt_payload(uint8_t crypt_alg, + const uint8_t * key, + const uint8_t * input, + uint32_t input_length, + uint8_t * output, + uint16_t * bytesWritten); +int lanplus_decrypt_payload(uint8_t crypt_alg, + const uint8_t * key, + const uint8_t * input, + uint32_t input_length, + uint8_t * output, + uint16_t * payload_size); +int lanplus_has_valid_auth_code(struct ipmi_rs * rs, + struct ipmi_session * session); + + + + +#endif /* IPMI_LANPLUS_CRYPT_H */ diff --git a/src/plugins/lanplus/lanplus_crypt_impl.c b/src/plugins/lanplus/lanplus_crypt_impl.c new file mode 100644 index 0000000..cde6c54 --- /dev/null +++ b/src/plugins/lanplus/lanplus_crypt_impl.c @@ -0,0 +1,293 @@ +/* + * 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 "ipmitool/log.h" +#include "ipmitool/ipmi_constants.h" +#include "lanplus.h" +#include "lanplus_crypt_impl.h" +#include <openssl/hmac.h> +#include <openssl/evp.h> +#include <openssl/rand.h> +#include <openssl/err.h> +#include <assert.h> + + + +/* + * lanplus_seed_prng + * + * Seed our PRNG with the specified number of bytes from /dev/random + * + * param bytes specifies the number of bytes to read from /dev/random + * + * returns 0 on success + * 1 on failure + */ +int lanplus_seed_prng(uint32_t bytes) +{ + if (! RAND_load_file("/dev/urandom", bytes)) + return 1; + else + return 0; +} + + + +/* + * lanplus_rand + * + * Generate a random number of the specified size + * + * param num_bytes [in] is the size of the random number to be + * generated + * param buffer [out] is where we will place our random number + * + * return 0 on success + * 1 on failure + */ +int +lanplus_rand(uint8_t * buffer, uint32_t num_bytes) +{ +#undef IPMI_LANPLUS_FAKE_RAND +#ifdef IPMI_LANPLUS_FAKE_RAND + + /* + * This code exists so that we can easily find the generated random number + * in the hex dumps. + */ + int i; + for (i = 0; i < num_bytes; ++i) + buffer[i] = 0x70 | i; + + return 0; +#else + return (! RAND_bytes(buffer, num_bytes)); +#endif +} + + + +/* + * lanplus_HMAC + * + * param mac specifies the algorithm to be used, currently only SHA1 is supported + * param key is the key used for HMAC generation + * param key_len is the lenght of key + * param d is the data to be MAC'd + * param n is the length of the data at d + * param md is the result of the HMAC algorithm + * param md_len is the length of md + * + * returns a pointer to md + */ +uint8_t * +lanplus_HMAC(uint8_t mac, + const void *key, + int key_len, + const uint8_t *d, + int n, + uint8_t *md, + uint32_t *md_len) +{ + const EVP_MD *evp_md = NULL; + + if ((mac == IPMI_AUTH_RAKP_HMAC_SHA1) || + (mac == IPMI_INTEGRITY_HMAC_SHA1_96)) + evp_md = EVP_sha1(); + else + { + lprintf(LOG_DEBUG, "Invalid mac type 0x%x in lanplus_HMAC\n", mac); + assert(0); + } + + return HMAC(evp_md, key, key_len, d, n, md, (unsigned int *)md_len); +} + + +/* + * lanplus_encrypt_aes_cbc_128 + * + * Encrypt with the AES CBC 128 algorithm + * + * param iv is the 16 byte initialization vector + * param key is the 16 byte key used by the AES algorithm + * param input is the data to be encrypted + * param input_length is the number of bytes to be encrypted. This MUST + * be a multiple of the block size, 16. + * param output is the encrypted output + * param bytes_written is the number of bytes written. This param is set + * to 0 on failure, or if 0 bytes were input. + */ +void +lanplus_encrypt_aes_cbc_128(const uint8_t * iv, + const uint8_t * key, + const uint8_t * input, + uint32_t input_length, + uint8_t * output, + uint32_t * bytes_written) +{ + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv); + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + + *bytes_written = 0; + + if (input_length == 0) + return; + + if (verbose >= 5) + { + printbuf(iv, 16, "encrypting with this IV"); + printbuf(key, 16, "encrypting with this key"); + printbuf(input, input_length, "encrypting this data"); + } + + + /* + * The default implementation adds a whole block of padding if the input + * data is perfectly aligned. We would like to keep that from happening. + * We have made a point to have our input perfectly padded. + */ + assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0); + + + if(!EVP_EncryptUpdate(&ctx, output, (int *)bytes_written, input, input_length)) + { + /* Error */ + *bytes_written = 0; + return; + } + else + { + uint32_t tmplen; + + if(!EVP_EncryptFinal_ex(&ctx, output + *bytes_written, (int *)&tmplen)) + { + *bytes_written = 0; + return; /* Error */ + } + else + { + /* Success */ + *bytes_written += tmplen; + EVP_CIPHER_CTX_cleanup(&ctx); + } + } +} + + + +/* + * lanplus_decrypt_aes_cbc_128 + * + * Decrypt with the AES CBC 128 algorithm + * + * param iv is the 16 byte initialization vector + * param key is the 16 byte key used by the AES algorithm + * param input is the data to be decrypted + * param input_length is the number of bytes to be decrypted. This MUST + * be a multiple of the block size, 16. + * param output is the decrypted output + * param bytes_written is the number of bytes written. This param is set + * to 0 on failure, or if 0 bytes were input. + */ +void +lanplus_decrypt_aes_cbc_128(const uint8_t * iv, + const uint8_t * key, + const uint8_t * input, + uint32_t input_length, + uint8_t * output, + uint32_t * bytes_written) +{ + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv); + EVP_CIPHER_CTX_set_padding(&ctx, 0); + + + if (verbose >= 5) + { + printbuf(iv, 16, "decrypting with this IV"); + printbuf(key, 16, "decrypting with this key"); + printbuf(input, input_length, "decrypting this data"); + } + + + *bytes_written = 0; + + if (input_length == 0) + return; + + /* + * The default implementation adds a whole block of padding if the input + * data is perfectly aligned. We would like to keep that from happening. + * We have made a point to have our input perfectly padded. + */ + assert((input_length % IPMI_CRYPT_AES_CBC_128_BLOCK_SIZE) == 0); + + + if (!EVP_DecryptUpdate(&ctx, output, (int *)bytes_written, input, input_length)) + { + /* Error */ + lprintf(LOG_DEBUG, "ERROR: decrypt update failed"); + *bytes_written = 0; + return; + } + else + { + uint32_t tmplen; + + if (!EVP_DecryptFinal_ex(&ctx, output + *bytes_written, (int *)&tmplen)) + { + char buffer[1000]; + ERR_error_string(ERR_get_error(), buffer); + lprintf(LOG_DEBUG, "the ERR error %s", buffer); + lprintf(LOG_DEBUG, "ERROR: decrypt final failed"); + *bytes_written = 0; + return; /* Error */ + } + else + { + /* Success */ + *bytes_written += tmplen; + EVP_CIPHER_CTX_cleanup(&ctx); + } + } + + if (verbose >= 5) + { + lprintf(LOG_DEBUG, "Decrypted %d encrypted bytes", input_length); + printbuf(output, *bytes_written, "Decrypted this data"); + } +} diff --git a/src/plugins/lanplus/lanplus_crypt_impl.h b/src/plugins/lanplus/lanplus_crypt_impl.h new file mode 100644 index 0000000..ff534bc --- /dev/null +++ b/src/plugins/lanplus/lanplus_crypt_impl.h @@ -0,0 +1,66 @@ +/* + * 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_LANPLUS_CRYPT_IMPL_H +#define IPMI_LANPLUS_CRYPT_IMPL_H + + +int +lanplus_seed_prng(uint32_t bytes); + +int +lanplus_rand(uint8_t * buffer, uint32_t num_bytes); + +uint8_t * +lanplus_HMAC(uint8_t mac, const void *key, int key_len, + const uint8_t *d, int n, uint8_t *md, + uint32_t *md_len); + +void +lanplus_encrypt_aes_cbc_128(const uint8_t * iv, + const uint8_t * key, + const uint8_t * input, + uint32_t input_length, + uint8_t * output, + uint32_t * bytes_written); + + +void +lanplus_decrypt_aes_cbc_128(const uint8_t * iv, + const uint8_t * key, + const uint8_t * input, + uint32_t input_length, + uint8_t * output, + uint32_t * bytes_written); + + +#endif /* IPMI_LANPLUS_CRYPT_IMPL_H */ diff --git a/src/plugins/lanplus/lanplus_dump.c b/src/plugins/lanplus/lanplus_dump.c new file mode 100644 index 0000000..8d52fab --- /dev/null +++ b/src/plugins/lanplus/lanplus_dump.c @@ -0,0 +1,192 @@ +/* + * 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 "lanplus.h" +#include "lanplus_dump.h" + +extern const struct valstr ipmi_rakp_return_codes[]; +extern const struct valstr ipmi_priv_levels[]; +extern const struct valstr ipmi_auth_algorithms[]; +extern const struct valstr ipmi_integrity_algorithms[]; +extern const struct valstr ipmi_encryption_algorithms[]; + +#define DUMP_PREFIX_INCOMING "<<" + +void lanplus_dump_open_session_response(const struct ipmi_rs * rsp) +{ + if (verbose < 2) + return; + + printf("%sOPEN SESSION RESPONSE\n", DUMP_PREFIX_INCOMING); + + printf("%s Message tag : 0x%02x\n", + DUMP_PREFIX_INCOMING, + rsp->payload.open_session_response.message_tag); + printf("%s RMCP+ status : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.open_session_response.rakp_return_code, + ipmi_rakp_return_codes)); + printf("%s Maximum privilege level : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.open_session_response.max_priv_level, + ipmi_priv_levels)); + printf("%s Console Session ID : 0x%08lx\n", + DUMP_PREFIX_INCOMING, + (long)rsp->payload.open_session_response.console_id); + + /* only tag, status, privlvl, and console id are returned if error */ + if (rsp->payload.open_session_response.rakp_return_code != + IPMI_RAKP_STATUS_NO_ERRORS) + return; + + printf("%s BMC Session ID : 0x%08lx\n", + DUMP_PREFIX_INCOMING, + (long)rsp->payload.open_session_response.bmc_id); + printf("%s Negotiated authenticatin algorithm : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.open_session_response.auth_alg, + ipmi_auth_algorithms)); + printf("%s Negotiated integrity algorithm : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.open_session_response.integrity_alg, + ipmi_integrity_algorithms)); + printf("%s Negotiated encryption algorithm : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.open_session_response.crypt_alg, + ipmi_encryption_algorithms)); + printf("\n"); +} + + + +void lanplus_dump_rakp2_message(const struct ipmi_rs * rsp, uint8_t auth_alg) +{ + int i; + + if (verbose < 2) + return; + + printf("%sRAKP 2 MESSAGE\n", DUMP_PREFIX_INCOMING); + + printf("%s Message tag : 0x%02x\n", + DUMP_PREFIX_INCOMING, + rsp->payload.rakp2_message.message_tag); + + printf("%s RMCP+ status : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.rakp2_message.rakp_return_code, + ipmi_rakp_return_codes)); + + printf("%s Console Session ID : 0x%08lx\n", + DUMP_PREFIX_INCOMING, + (long)rsp->payload.rakp2_message.console_id); + + printf("%s BMC random number : 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < 16; ++i) + printf("%02x", rsp->payload.rakp2_message.bmc_rand[i]); + printf("\n"); + + printf("%s BMC GUID : 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < 16; ++i) + printf("%02x", rsp->payload.rakp2_message.bmc_guid[i]); + printf("\n"); + + switch(auth_alg) + { + case IPMI_AUTH_RAKP_NONE: + printf("%s Key exchange auth code : none\n", DUMP_PREFIX_INCOMING); + break; + case IPMI_AUTH_RAKP_HMAC_SHA1: + printf("%s Key exchange auth code [sha1] : 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < 20; ++i) + printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]); + printf("\n"); + break; + case IPMI_AUTH_RAKP_HMAC_MD5: + printf("%s Key exchange auth code [md5] : 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < 16; ++i) + printf("%02x", rsp->payload.rakp2_message.key_exchange_auth_code[i]); + printf("\n"); + break; + default: + printf("%s Key exchange auth code : invalid", DUMP_PREFIX_INCOMING); + } + printf("\n"); +} + + + +void lanplus_dump_rakp4_message(const struct ipmi_rs * rsp, uint8_t auth_alg) +{ + int i; + + if (verbose < 2) + return; + + printf("%sRAKP 4 MESSAGE\n", DUMP_PREFIX_INCOMING); + + printf("%s Message tag : 0x%02x\n", + DUMP_PREFIX_INCOMING, + rsp->payload.rakp4_message.message_tag); + + printf("%s RMCP+ status : %s\n", + DUMP_PREFIX_INCOMING, + val2str(rsp->payload.rakp4_message.rakp_return_code, + ipmi_rakp_return_codes)); + + printf("%s Console Session ID : 0x%08lx\n", + DUMP_PREFIX_INCOMING, + (long)rsp->payload.rakp4_message.console_id); + + switch(auth_alg) + { + case IPMI_AUTH_RAKP_NONE: + printf("%s Key exchange auth code : none\n", DUMP_PREFIX_INCOMING); + break; + case IPMI_AUTH_RAKP_HMAC_SHA1: + printf("%s Key exchange auth code [sha1] : 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < 12; ++i) + printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]); + printf("\n"); + break; + case IPMI_AUTH_RAKP_HMAC_MD5: + printf("%s Key exchange auth code [md5] : 0x", DUMP_PREFIX_INCOMING); + for (i = 0; i < 12; ++i) + printf("%02x", rsp->payload.rakp4_message.integrity_check_value[i]); + printf("\n"); + break; + default: + printf("%s Key exchange auth code : invalid", DUMP_PREFIX_INCOMING); + } + printf("\n"); +} + diff --git a/src/plugins/lanplus/lanplus_dump.h b/src/plugins/lanplus/lanplus_dump.h new file mode 100644 index 0000000..4e29ebb --- /dev/null +++ b/src/plugins/lanplus/lanplus_dump.h @@ -0,0 +1,45 @@ +/* + * 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_LANPLUS_DUMP_H +#define IPMI_LANPLUS_DUMP_H + +#include <ipmitool/ipmi_intf.h> + +/* See the implementation file for documentation */ +void lanplus_dump_open_session_response(const struct ipmi_rs * rsp); +void lanplus_dump_rakp2_message(const struct ipmi_rs * rsp, uint8_t auth_alg); +void lanplus_dump_rakp4_message(const struct ipmi_rs * rsp, uint8_t auth_alg); + + +#endif /* IPMI_LANPLUS_DUMP_H */ diff --git a/src/plugins/lanplus/lanplus_strings.c b/src/plugins/lanplus/lanplus_strings.c new file mode 100644 index 0000000..074f898 --- /dev/null +++ b/src/plugins/lanplus/lanplus_strings.c @@ -0,0 +1,39 @@ +#include "lanplus.h" +#include "ipmitool/ipmi_constants.h" + +const struct valstr ipmi_rakp_return_codes[] = { + + { IPMI_RAKP_STATUS_NO_ERRORS, "no errors" }, + { IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_SESSION, "insufficient resources for session" }, + { IPMI_RAKP_STATUS_INVALID_SESSION_ID, "invalid session ID" }, + { IPMI_RAKP_STATUS_INVALID_PAYLOAD_TYPE, "invalid payload type" }, + { IPMI_RAKP_STATUS_INVALID_AUTHENTICATION_ALGORITHM, "invalid authentication algorithm" }, + { IPMI_RAKP_STATUS_INVALID_INTEGRITTY_ALGORITHM, "invalid integrity algorithm" }, + { IPMI_RAKP_STATUS_NO_MATCHING_AUTHENTICATION_PAYLOAD, "no matching authentication algorithm"}, + { IPMI_RAKP_STATUS_NO_MATCHING_INTEGRITY_PAYLOAD, "no matching integrity payload" }, + { IPMI_RAKP_STATUS_INACTIVE_SESSION_ID, "inactive session ID" }, + { IPMI_RAKP_STATUS_INVALID_ROLE, "invalid role" }, + { IPMI_RAKP_STATUS_UNAUTHORIZED_ROLE_REQUESTED, "unauthorized role requested" }, + { IPMI_RAKP_STATUS_INSUFFICIENT_RESOURCES_FOR_ROLE, "insufficient resources for role" }, + { IPMI_RAKP_STATUS_INVALID_NAME_LENGTH, "invalid name length" }, + { IPMI_RAKP_STATUS_UNAUTHORIZED_NAME, "unauthorized name" }, + { IPMI_RAKP_STATUS_UNAUTHORIZED_GUID, "unauthorized GUID" }, + { IPMI_RAKP_STATUS_INVALID_INTEGRITY_CHECK_VALUE, "invalid integrity check value" }, + { IPMI_RAKP_STATUS_INVALID_CONFIDENTIALITY_ALGORITHM, "invalid confidentiality algorithm" }, + { IPMI_RAKP_STATUS_NO_CIPHER_SUITE_MATCH, "no matching cipher suite" }, + { IPMI_RAKP_STATUS_ILLEGAL_PARAMTER, "illegal parameter" }, + { 0, 0 }, +}; + + +const struct valstr ipmi_priv_levels[] = { + { IPMI_PRIV_CALLBACK, "callback" }, + { IPMI_PRIV_USER, "user" }, + { IPMI_PRIV_OPERATOR, "operator" }, + { IPMI_PRIV_ADMIN, "admin" }, + { IPMI_PRIV_OEM, "oem" }, + { 0, 0 }, +}; + + + diff --git a/src/plugins/lanplus/rmcp.h b/src/plugins/lanplus/rmcp.h new file mode 100644 index 0000000..51dc44d --- /dev/null +++ b/src/plugins/lanplus/rmcp.h @@ -0,0 +1,82 @@ +/* + * 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_RMCP_H +#define IPMI_RMCP_H + +#include <ipmitool/helper.h> +#include "lanplus.h" + +#define RMCP_VERSION_1 0x06 + +#define RMCP_UDP_PORT 0x26f /* port 623 */ +#define RMCP_UDP_SECURE_PORT 0x298 /* port 664 */ + +#define RMCP_TYPE_MASK 0x80 +#define RMCP_TYPE_NORM 0x00 +#define RMCP_TYPE_ACK 0x01 + +static const struct valstr rmcp_type_vals[] __attribute__((unused)) = { + { RMCP_TYPE_NORM, "Normal RMCP" }, + { RMCP_TYPE_ACK, "RMCP ACK" }, + { 0, NULL } +}; + +#define RMCP_CLASS_MASK 0x1f +#define RMCP_CLASS_ASF 0x06 +#define RMCP_CLASS_IPMI 0x07 +#define RMCP_CLASS_OEM 0x08 + +static const struct valstr rmcp_class_vals[] __attribute__((unused)) = { + { RMCP_CLASS_ASF, "ASF" }, + { RMCP_CLASS_IPMI, "IPMI" }, + { RMCP_CLASS_OEM, "OEM" }, + { 0, NULL } +}; + +/* RMCP message header */ +#ifdef HAVE_PRAGMA_PACK +#pragma pack(1) +#endif +struct rmcp_hdr { + uint8_t ver; + uint8_t __reserved; + uint8_t seq; + uint8_t class; +} ATTRIBUTE_PACKING; +#ifdef HAVE_PRAGMA_PACK +#pragma pack(0) +#endif + +int handle_rmcp(struct ipmi_intf * intf, uint8_t * data, int data_len); + +#endif /* IPMI_RMCP_H */ diff --git a/src/plugins/lipmi/Makefile.am b/src/plugins/lipmi/Makefile.am new file mode 100644 index 0000000..61c50f4 --- /dev/null +++ b/src/plugins/lipmi/Makefile.am @@ -0,0 +1,39 @@ +# 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_lipmi.la +noinst_LTLIBRARIES = @INTF_LIPMI_LIB@ +libintf_lipmi_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_lipmi_la_SOURCES = lipmi.c + diff --git a/src/plugins/lipmi/Makefile.in b/src/plugins/lipmi/Makefile.in new file mode 100644 index 0000000..2e97922 --- /dev/null +++ b/src/plugins/lipmi/Makefile.in @@ -0,0 +1,538 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/lipmi +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_lipmi_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_lipmi_la_OBJECTS = lipmi.lo +libintf_lipmi_la_OBJECTS = $(am_libintf_lipmi_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_lipmi_la_SOURCES) +DIST_SOURCES = $(libintf_lipmi_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_lipmi.la +noinst_LTLIBRARIES = @INTF_LIPMI_LIB@ +libintf_lipmi_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_lipmi_la_SOURCES = lipmi.c +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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/lipmi/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/lipmi/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_lipmi.la: $(libintf_lipmi_la_OBJECTS) $(libintf_lipmi_la_DEPENDENCIES) $(EXTRA_libintf_lipmi_la_DEPENDENCIES) + $(LINK) $(libintf_lipmi_la_OBJECTS) $(libintf_lipmi_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lipmi.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/lipmi/lipmi.c b/src/plugins/lipmi/lipmi.c new file mode 100644 index 0000000..fa7845d --- /dev/null +++ b/src/plugins/lipmi/lipmi.c @@ -0,0 +1,129 @@ +/* + * 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 <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stropts.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> + +#include <sys/lipmi/lipmi_intf.h> + +#define IPMI_LIPMI_DEV "/dev/lipmi" + +extern int verbose; + +static int ipmi_lipmi_open(struct ipmi_intf * intf) +{ + intf->fd = open(IPMI_LIPMI_DEV, O_RDWR); + if (intf->fd < 0) { + perror("Could not open lipmi device"); + return -1; + } + intf->opened = 1; + intf->manufacturer_id = ipmi_get_oem(intf); + return intf->fd; +} + +static void ipmi_lipmi_close(struct ipmi_intf * intf) +{ + if (intf && intf->fd >= 0) + close(intf->fd); + intf->fd = -1; + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; +} + +static struct ipmi_rs * ipmi_lipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + struct strioctl istr; + static struct lipmi_reqrsp reqrsp; + static struct ipmi_rs rsp; + static int curr_seq = 0; + + if (!intf || !req) + return NULL; + + if (!intf->opened && intf->open && intf->open(intf) < 0) + return NULL; + + memset(&reqrsp, 0, sizeof(reqrsp)); + reqrsp.req.fn = req->msg.netfn; + reqrsp.req.lun = 0; + reqrsp.req.cmd = req->msg.cmd; + reqrsp.req.datalength = req->msg.data_len; + memcpy(reqrsp.req.data, req->msg.data, req->msg.data_len); + reqrsp.rsp.datalength = RECV_MAX_PAYLOAD_SIZE; + + istr.ic_cmd = IOCTL_IPMI_KCS_ACTION; + istr.ic_timout = 0; + istr.ic_dp = (char *)&reqrsp; + istr.ic_len = sizeof(struct lipmi_reqrsp); + + if (verbose > 1) { + printf("LIPMI req.fn : %x\n", reqrsp.req.fn); + printf("LIPMI req.lun : %x\n", reqrsp.req.lun); + printf("LIPMI req.cmd : %x\n", reqrsp.req.cmd); + printf("LIPMI req.datalength : %d\n", reqrsp.req.datalength); + } + + if (ioctl(intf->fd, I_STR, &istr) < 0) { + perror("LIPMI IOCTL: I_STR"); + return NULL; + } + + memset(&rsp, 0, sizeof(struct ipmi_rs)); + rsp.ccode = reqrsp.rsp.ccode; + rsp.data_len = reqrsp.rsp.datalength; + + if (!rsp.ccode && rsp.data_len) + memcpy(rsp.data, reqrsp.rsp.data, rsp.data_len); + + return &rsp; +} + +struct ipmi_intf ipmi_lipmi_intf = { + name: "lipmi", + desc: "Solaris x86 LIPMI Interface", + open: ipmi_lipmi_open, + close: ipmi_lipmi_close, + sendrecv: ipmi_lipmi_send_cmd, + target_addr: IPMI_BMC_SLAVE_ADDR, +}; + diff --git a/src/plugins/open/Makefile.am b/src/plugins/open/Makefile.am new file mode 100644 index 0000000..89ce711 --- /dev/null +++ b/src/plugins/open/Makefile.am @@ -0,0 +1,39 @@ +# 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. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_open.la +noinst_LTLIBRARIES = @INTF_OPEN_LIB@ +libintf_open_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_open_la_SOURCES = open.c open.h + diff --git a/src/plugins/open/Makefile.in b/src/plugins/open/Makefile.in new file mode 100644 index 0000000..d6b1f26 --- /dev/null +++ b/src/plugins/open/Makefile.in @@ -0,0 +1,538 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# 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. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/open +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_open_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_open_la_OBJECTS = open.lo +libintf_open_la_OBJECTS = $(am_libintf_open_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_open_la_SOURCES) +DIST_SOURCES = $(libintf_open_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_open.la +noinst_LTLIBRARIES = @INTF_OPEN_LIB@ +libintf_open_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_open_la_SOURCES = open.c open.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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/open/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/open/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_open.la: $(libintf_open_la_OBJECTS) $(libintf_open_la_DEPENDENCIES) $(EXTRA_libintf_open_la_DEPENDENCIES) + $(LINK) $(libintf_open_la_OBJECTS) $(libintf_open_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/open.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/open/open.c b/src/plugins/open/open.c new file mode 100644 index 0000000..92b6f37 --- /dev/null +++ b/src/plugins/open/open.c @@ -0,0 +1,439 @@ +/* + * 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 <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/helper.h> +#include <ipmitool/log.h> + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#if defined(HAVE_SYS_IOCCOM_H) +# include <sys/ioccom.h> +#endif + +#if defined(HAVE_OPENIPMI_H) +# if defined(HAVE_LINUX_COMPILER_H) +# include <linux/compiler.h> +# endif +# include <linux/ipmi.h> +#elif defined(HAVE_FREEBSD_IPMI_H) +/* FreeBSD OpenIPMI-compatible header */ +# include <sys/ipmi.h> +#else +# include "open.h" +#endif + +/** + * Maximum input message size for KCS/SMIC is 40 with 2 utility bytes and + * 38 bytes of data. + * Maximum input message size for BT is 42 with 4 utility bytes and + * 38 bytes of data. + */ +#define IPMI_OPENIPMI_MAX_RQ_DATA_SIZE 38 + +/** + * Maximum output message size for KCS/SMIC is 38 with 2 utility bytes, a byte + * for completion code and 35 bytes of data. + * Maximum output message size for BT is 40 with 4 utility bytes, a byte + * for completion code and 35 bytes of data. + */ +#define IPMI_OPENIPMI_MAX_RS_DATA_SIZE 35 + +extern int verbose; + +static int +ipmi_openipmi_open(struct ipmi_intf * intf) +{ + int i = 0; + + char ipmi_dev[16]; + char ipmi_devfs[16]; + char ipmi_devfs2[16]; + int devnum = 0; + + devnum = intf->devnum; + + sprintf(ipmi_dev, "/dev/ipmi%d", devnum); + sprintf(ipmi_devfs, "/dev/ipmi/%d", devnum); + sprintf(ipmi_devfs2, "/dev/ipmidev/%d", devnum); + lprintf(LOG_DEBUG, "Using ipmi device %d", devnum); + + intf->fd = open(ipmi_dev, O_RDWR); + + if (intf->fd < 0) { + intf->fd = open(ipmi_devfs, O_RDWR); + if (intf->fd < 0) { + intf->fd = open(ipmi_devfs2, O_RDWR); + } + if (intf->fd < 0) { + lperror(LOG_ERR, "Could not open device at %s or %s or %s", + ipmi_dev, ipmi_devfs , ipmi_devfs2); + return -1; + } + } + + if (ioctl(intf->fd, IPMICTL_SET_GETS_EVENTS_CMD, &i) < 0) { + lperror(LOG_ERR, "Could not enable event receiver"); + return -1; + } + + intf->opened = 1; + + /* This is never set to 0, the default is IPMI_BMC_SLAVE_ADDR */ + if (intf->my_addr != 0) { + if (intf->set_my_addr(intf, intf->my_addr) < 0) { + lperror(LOG_ERR, "Could not set IPMB address"); + return -1; + } + lprintf(LOG_DEBUG, "Set IPMB address to 0x%x", + intf->my_addr ); + } + + intf->manufacturer_id = ipmi_get_oem(intf); + return intf->fd; +} +static int +ipmi_openipmi_set_my_addr(struct ipmi_intf *intf, uint8_t addr) +{ + unsigned int a = addr; + if (ioctl(intf->fd, IPMICTL_SET_MY_ADDRESS_CMD, &a) < 0) { + lperror(LOG_ERR, "Could not set IPMB address"); + return -1; + } + intf->my_addr = addr; + return 0; +} + +static void +ipmi_openipmi_close(struct ipmi_intf * intf) +{ + if (intf->fd >= 0) { + close(intf->fd); + intf->fd = -1; + } + + intf->opened = 0; + intf->manufacturer_id = IPMI_OEM_UNKNOWN; +} + +static struct ipmi_rs * +ipmi_openipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + struct ipmi_recv recv; + struct ipmi_addr addr; + struct ipmi_system_interface_addr bmc_addr = { + addr_type: IPMI_SYSTEM_INTERFACE_ADDR_TYPE, + channel: IPMI_BMC_CHANNEL, + }; + struct ipmi_ipmb_addr ipmb_addr = { + addr_type: IPMI_IPMB_ADDR_TYPE, + }; + struct ipmi_req _req; + static struct ipmi_rs rsp; + static int curr_seq = 0; + fd_set rset; + + uint8_t * data = NULL; + int data_len = 0; + + + if (intf == NULL || req == NULL) + return NULL; + + ipmb_addr.channel = intf->target_channel & 0x0f; + + if (intf->opened == 0 && intf->open != NULL) + if (intf->open(intf) < 0) + return NULL; + + if (verbose > 2) + printbuf(req->msg.data, req->msg.data_len, + "OpenIPMI Request Message"); + + /* + * setup and send message + */ + + memset(&_req, 0, sizeof(struct ipmi_req)); + + if (intf->target_addr != 0 && + intf->target_addr != intf->my_addr) { + /* use IPMB address if needed */ + ipmb_addr.slave_addr = intf->target_addr; + ipmb_addr.lun = req->msg.lun; + lprintf(LOG_DEBUG, "Sending request 0x%x to " + "IPMB target @ 0x%x:0x%x (from 0x%x)", + req->msg.cmd, + intf->target_addr,intf->target_channel, intf->my_addr); + + if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) { + uint8_t index = 0; + + lprintf(LOG_DEBUG, "Encapsulating data sent to " + "end target [0x%02x,0x%02x] using transit [0x%02x,0x%02x] from 0x%x ", + (0x40 | intf->target_channel), + intf->target_addr, + intf->transit_channel, + intf->transit_addr, + intf->my_addr + ); + + /* Convert Message to 'Send Message' */ + /* Supplied req : req , internal req : _req */ + + if (verbose > 4) { + fprintf(stderr, "Converting message:\n"); + fprintf(stderr, " netfn = 0x%x\n", req->msg.netfn ); + fprintf(stderr, " cmd = 0x%x\n", req->msg.cmd); + if (recv.msg.data && recv.msg.data_len) { + fprintf(stderr, " data_len = %d\n", req->msg.data_len); + fprintf(stderr, " data = %s\n", + buf2str(req->msg.data,req->msg.data_len)); + } + } + + /* Modify target address to use 'transit' instead */ + ipmb_addr.slave_addr = intf->transit_addr; + ipmb_addr.channel = intf->transit_channel; + + /* FIXME backup "My address" */ + data_len = req->msg.data_len + 8; + data = malloc(data_len); + if (data == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return NULL; + } + + memset(data, 0, data_len); + + data[index++] = (0x40|intf->target_channel); + data[index++] = intf->target_addr; + data[index++] = ( req->msg.netfn << 2 ) | req->msg.lun ; + data[index++] = ipmi_csum(data+1, 2); + data[index++] = 0xFF; /* normally 0x20 , overwritten by IPMC */ + data[index++] = ( (0) << 2) | 0 ; /* FIXME */ + data[index++] = req->msg.cmd; + memcpy( (data+index) , req->msg.data, req->msg.data_len); + index += req->msg.data_len; + data[index++] = ipmi_csum( (data+4),(req->msg.data_len + 3) ); + + if (verbose > 4) { + fprintf(stderr, "Encapsulated message:\n"); + fprintf(stderr, " netfn = 0x%x\n", IPMI_NETFN_APP ); + fprintf(stderr, " cmd = 0x%x\n", 0x34 ); + if (data && data_len) { + fprintf(stderr, " data_len = %d\n", data_len); + fprintf(stderr, " data = %s\n", + buf2str(data,data_len)); + } + } + } + _req.addr = (unsigned char *) &ipmb_addr; + _req.addr_len = sizeof(ipmb_addr); + } else { + /* otherwise use system interface */ + lprintf(LOG_DEBUG+2, "Sending request 0x%x to " + "System Interface", req->msg.cmd); + bmc_addr.lun = req->msg.lun; + _req.addr = (unsigned char *) &bmc_addr; + _req.addr_len = sizeof(bmc_addr); + } + + _req.msgid = curr_seq++; + + /* In case of a bridge request */ + if( data != NULL && data_len != 0 ) { + _req.msg.data = data; + _req.msg.data_len = data_len; + _req.msg.netfn = IPMI_NETFN_APP; + _req.msg.cmd = 0x34; + + } else { + _req.msg.data = req->msg.data; + _req.msg.data_len = req->msg.data_len; + _req.msg.netfn = req->msg.netfn; + _req.msg.cmd = req->msg.cmd; + } + + if (ioctl(intf->fd, IPMICTL_SEND_COMMAND, &_req) < 0) { + lperror(LOG_ERR, "Unable to send command"); + if (data != NULL) { + free(data); + data = NULL; + } + return NULL; + } + + /* + * wait for and retrieve response + */ + + if (intf->noanswer) { + if (data != NULL) { + free(data); + data = NULL; + } + return NULL; + } + + FD_ZERO(&rset); + FD_SET(intf->fd, &rset); + + if (select(intf->fd+1, &rset, NULL, NULL, NULL) < 0) { + lperror(LOG_ERR, "I/O Error"); + if (data != NULL) { + free(data); + data = NULL; + } + return NULL; + } + if (FD_ISSET(intf->fd, &rset) == 0) { + lprintf(LOG_ERR, "No data available"); + if (data != NULL) { + free(data); + data = NULL; + } + return NULL; + } + + recv.addr = (unsigned char *) &addr; + recv.addr_len = sizeof(addr); + recv.msg.data = rsp.data; + recv.msg.data_len = sizeof(rsp.data); + + /* get data */ + if (ioctl(intf->fd, IPMICTL_RECEIVE_MSG_TRUNC, &recv) < 0) { + lperror(LOG_ERR, "Error receiving message"); + if (errno != EMSGSIZE) { + if (data != NULL) { + free(data); + data = NULL; + } + return NULL; + } + } + + if (verbose > 4) { + fprintf(stderr, "Got message:"); + fprintf(stderr, " type = %d\n", recv.recv_type); + fprintf(stderr, " channel = 0x%x\n", addr.channel); + fprintf(stderr, " msgid = %ld\n", recv.msgid); + fprintf(stderr, " netfn = 0x%x\n", recv.msg.netfn); + fprintf(stderr, " cmd = 0x%x\n", recv.msg.cmd); + if (recv.msg.data && recv.msg.data_len) { + fprintf(stderr, " data_len = %d\n", recv.msg.data_len); + fprintf(stderr, " data = %s\n", + buf2str(recv.msg.data, recv.msg.data_len)); + } + } + + if(intf->transit_addr != 0 && intf->transit_addr != intf->my_addr) { + uint8_t index = 0; + + /* ipmb_addr.transit_slave_addr = intf->transit_addr; */ + lprintf(LOG_DEBUG, "Decapsulating data received from transit " + "IPMB target @ 0x%x", intf->transit_addr); + + /* comp code */ + /* Check data */ + + if( recv.msg.data[0] == 0 ) { + recv.msg.netfn = recv.msg.data[2] >> 2; + recv.msg.cmd = recv.msg.data[6]; + + recv.msg.data = memmove(recv.msg.data ,recv.msg.data+7 , recv.msg.data_len - 7); + recv.msg.data_len -=8; + + if (verbose > 4) { + fprintf(stderr, "Decapsulated message:\n"); + fprintf(stderr, " netfn = 0x%x\n", recv.msg.netfn ); + fprintf(stderr, " cmd = 0x%x\n", recv.msg.cmd); + if (recv.msg.data && recv.msg.data_len) { + fprintf(stderr, " data_len = %d\n", recv.msg.data_len); + fprintf(stderr, " data = %s\n", + buf2str(recv.msg.data,recv.msg.data_len)); + } + } + } + } + + /* save completion code */ + rsp.ccode = recv.msg.data[0]; + rsp.data_len = recv.msg.data_len - 1; + + /* save response data for caller */ + if (rsp.ccode == 0 && rsp.data_len > 0) { + memmove(rsp.data, rsp.data + 1, rsp.data_len); + rsp.data[rsp.data_len] = 0; + } + + if (data != NULL) { + free(data); + data = NULL; + } + + return &rsp; +} + +int ipmi_openipmi_setup(struct ipmi_intf * intf) +{ + /* set default payload size */ + intf->max_request_data_size = IPMI_OPENIPMI_MAX_RQ_DATA_SIZE; + intf->max_response_data_size = IPMI_OPENIPMI_MAX_RS_DATA_SIZE; + + return 0; +} + +struct ipmi_intf ipmi_open_intf = { + name: "open", + desc: "Linux OpenIPMI Interface", + setup: ipmi_openipmi_setup, + open: ipmi_openipmi_open, + close: ipmi_openipmi_close, + sendrecv: ipmi_openipmi_send_cmd, + set_my_addr: ipmi_openipmi_set_my_addr, + my_addr: IPMI_BMC_SLAVE_ADDR, + target_addr: 0, /* init so -m local_addr does not cause bridging */ +}; diff --git a/src/plugins/open/open.h b/src/plugins/open/open.h new file mode 100644 index 0000000..5d7aa5b --- /dev/null +++ b/src/plugins/open/open.h @@ -0,0 +1,106 @@ +/* + * 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_OPENIPMI_H +#define IPMI_OPENIPMI_H + +#define IPMI_MAX_ADDR_SIZE 0x20 +#define IPMI_BMC_CHANNEL 0xf +#define IPMI_NUM_CHANNELS 0x10 + +#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c +#define IPMI_IPMB_ADDR_TYPE 0x01 +#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41 + +#define IPMI_RESPONSE_RECV_TYPE 1 +#define IPMI_ASYNC_EVENT_RECV_TYPE 2 +#define IPMI_CMD_RECV_TYPE 3 + +struct ipmi_addr { + int addr_type; + short channel; + char data[IPMI_MAX_ADDR_SIZE]; +}; + +struct ipmi_msg { + unsigned char netfn; + unsigned char cmd; + unsigned short data_len; + unsigned char *data; +}; + +struct ipmi_req { + unsigned char *addr; + unsigned int addr_len; + long msgid; + struct ipmi_msg msg; +}; + +struct ipmi_recv { + int recv_type; + unsigned char *addr; + unsigned int addr_len; + long msgid; + struct ipmi_msg msg; +}; + +struct ipmi_cmdspec { + unsigned char netfn; + unsigned char cmd; +}; + +struct ipmi_system_interface_addr { + int addr_type; + short channel; + unsigned char lun; +}; + +struct ipmi_ipmb_addr { + int addr_type; + short channel; + unsigned char slave_addr; + unsigned char lun; +}; + +#define IPMI_IOC_MAGIC 'i' +#define IPMICTL_RECEIVE_MSG_TRUNC _IOWR(IPMI_IOC_MAGIC, 11, struct ipmi_recv) +#define IPMICTL_RECEIVE_MSG _IOWR(IPMI_IOC_MAGIC, 12, struct ipmi_recv) +#define IPMICTL_SEND_COMMAND _IOR(IPMI_IOC_MAGIC, 13, struct ipmi_req) +#define IPMICTL_REGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 14, struct ipmi_cmdspec) +#define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, struct ipmi_cmdspec) +#define IPMICTL_SET_GETS_EVENTS_CMD _IOR(IPMI_IOC_MAGIC, 16, int) +#define IPMICTL_SET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 17, unsigned int) +#define IPMICTL_GET_MY_ADDRESS_CMD _IOR(IPMI_IOC_MAGIC, 18, unsigned int) +#define IPMICTL_SET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 19, unsigned int) +#define IPMICTL_GET_MY_LUN_CMD _IOR(IPMI_IOC_MAGIC, 20, unsigned int) + +#endif /*IPMI_OPENIPMI_H*/ diff --git a/src/plugins/serial/Makefile.am b/src/plugins/serial/Makefile.am new file mode 100644 index 0000000..5bfbd0d --- /dev/null +++ b/src/plugins/serial/Makefile.am @@ -0,0 +1,38 @@ +# * Copyright (c) 2012 Pigeon Point Systems. 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 Pigeon Point Systems, 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. +# PIGEON POINT SYSTEMS ("PPS") 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 +# PPS 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 PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I$(top_srcdir)/include + +EXTRA_LTLIBRARIES = libintf_serial.la +noinst_LTLIBRARIES = @INTF_SERIAL_LIB@ +libintf_serial_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_serial_la_SOURCES = serial_terminal.c serial_basic.c diff --git a/src/plugins/serial/Makefile.in b/src/plugins/serial/Makefile.in new file mode 100644 index 0000000..5abad44 --- /dev/null +++ b/src/plugins/serial/Makefile.in @@ -0,0 +1,539 @@ +# Makefile.in generated by automake 1.11.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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@ + +# * Copyright (c) 2012 Pigeon Point Systems. 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 Pigeon Point Systems, 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. +# PIGEON POINT SYSTEMS ("PPS") 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 +# PPS 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 PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +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@ +target_triplet = @target@ +subdir = src/plugins/serial +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libintf_serial_la_DEPENDENCIES = $(top_builddir)/lib/libipmitool.la +am_libintf_serial_la_OBJECTS = serial_terminal.lo serial_basic.lo +libintf_serial_la_OBJECTS = $(am_libintf_serial_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libintf_serial_la_SOURCES) +DIST_SOURCES = $(libintf_serial_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +ARCH = @ARCH@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BASEDIR = @BASEDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTRO = @DISTRO@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTF_BMC = @INTF_BMC@ +INTF_BMC_LIB = @INTF_BMC_LIB@ +INTF_DUMMY = @INTF_DUMMY@ +INTF_DUMMY_LIB = @INTF_DUMMY_LIB@ +INTF_FREE = @INTF_FREE@ +INTF_FREE_LIB = @INTF_FREE_LIB@ +INTF_IMB = @INTF_IMB@ +INTF_IMB_LIB = @INTF_IMB_LIB@ +INTF_LAN = @INTF_LAN@ +INTF_LANPLUS = @INTF_LANPLUS@ +INTF_LANPLUS_LIB = @INTF_LANPLUS_LIB@ +INTF_LAN_LIB = @INTF_LAN_LIB@ +INTF_LIPMI = @INTF_LIPMI@ +INTF_LIPMI_LIB = @INTF_LIPMI_LIB@ +INTF_OPEN = @INTF_OPEN@ +INTF_OPEN_LIB = @INTF_OPEN_LIB@ +INTF_SERIAL = @INTF_SERIAL@ +INTF_SERIAL_LIB = @INTF_SERIAL_LIB@ +IPMITOOL_INTF_LIB = @IPMITOOL_INTF_LIB@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS = @OS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POW_LIB = @POW_LIB@ +PSTAMP = @PSTAMP@ +RANLIB = @RANLIB@ +RPMBUILD = @RPMBUILD@ +RPM_RELEASE = @RPM_RELEASE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_configure_args = @ac_configure_args@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +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@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +INCLUDES = -I$(top_srcdir)/include +EXTRA_LTLIBRARIES = libintf_serial.la +noinst_LTLIBRARIES = @INTF_SERIAL_LIB@ +libintf_serial_la_LIBADD = $(top_builddir)/lib/libipmitool.la +libintf_serial_la_SOURCES = serial_terminal.c serial_basic.c +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 ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/serial/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/serial/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 +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libintf_serial.la: $(libintf_serial_la_OBJECTS) $(libintf_serial_la_DEPENDENCIES) $(EXTRA_libintf_serial_la_DEPENDENCIES) + $(LINK) $(libintf_serial_la_OBJECTS) $(libintf_serial_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serial_basic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serial_terminal.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@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@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@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 + +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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + 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; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__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)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$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 $(LTLIBRARIES) +installdirs: +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: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + 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 + + +# 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/src/plugins/serial/serial_basic.c b/src/plugins/serial/serial_basic.c new file mode 100644 index 0000000..5f4b926 --- /dev/null +++ b/src/plugins/serial/serial_basic.c @@ -0,0 +1,1029 @@ +/* + * Copyright (c) 2012 Pigeon Point Systems. 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 Pigeon Point Systems nor 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. + * PIGEON POINT SYSTEMS ("PPS") 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 + * PPS 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 PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* Serial Interface, Basic Mode plugin. */ + +#include <stdio.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/poll.h> +#include <termios.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/helper.h> +#include <ipmitool/log.h> + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#define SERIAL_BM_MAX_MSG_SIZE 47 +#define SERIAL_BM_MAX_RQ_SIZE 33 /* 40 - 7 */ +#define SERIAL_BM_MAX_RS_SIZE 32 /* 40 - 8 */ +#define SERIAL_BM_TIMEOUT 5 +#define SERIAL_BM_RETRY_COUNT 5 +#define SERIAL_BM_MAX_BUFFER_SIZE 250 + +#define BM_START 0xA0 +#define BM_STOP 0xA5 +#define BM_HANDSHAKE 0xA6 +#define BM_ESCAPE 0xAA + +/* + * IPMB message header + */ +struct ipmb_msg_hdr { + unsigned char rsSA; + unsigned char netFn; /* NET FN | RS LUN */ + unsigned char csum1; + unsigned char rqSA; + unsigned char rqSeq; /* RQ SEQ | RQ LUN */ + unsigned char cmd; + unsigned char data[0]; +}; + +/* + * Send Message command request for IPMB-format + */ +struct ipmi_send_message_rq { + unsigned char channel; + struct ipmb_msg_hdr msg; +}; + +/* + * Get Message command response for IPMB-format + */ +struct ipmi_get_message_rp { + unsigned char completion; + unsigned char channel; + unsigned char netFn; + unsigned char csum1; + unsigned char rsSA; + unsigned char rqSeq; + unsigned char cmd; + unsigned char data[0]; +}; + +/* + * State for the received message + */ +enum { + MSG_NONE, + MSG_IN_PROGRESS, + MSG_DONE +}; + +/* + * Message parsing context + */ +struct serial_bm_parse_ctx{ + int state; + uint8_t * msg; + size_t msg_len; + size_t max_len; + int escape; +}; + +/* + * Receiving context + */ +struct serial_bm_recv_ctx { + char buffer[SERIAL_BM_MAX_BUFFER_SIZE]; + size_t buffer_size; + size_t max_buffer_size; +}; + +/* + * Sending context + */ +struct serial_bm_request_ctx { + uint8_t rsSA; + uint8_t netFn; + uint8_t rqSA; + uint8_t rqSeq; + uint8_t cmd; +}; + +/* + * Table of supported baud rates + */ +static const struct { + int baudinit; + int baudrate; +} rates[] = { + { B2400, 2400 }, + { B9600, 9600 }, + { B19200, 19200 }, + { B38400, 38400 }, + { B57600, 57600 }, + { B115200, 115200 }, + { B230400, 230400 }, +#ifdef B460800 + { B460800, 460800 }, +#endif +}; + +/* + * Table of special characters + */ +static const struct { + uint8_t character; + uint8_t escape; +} characters[] = { + { BM_START, 0xB0 }, /* start */ + { BM_STOP, 0xB5 }, /* stop */ + { BM_HANDSHAKE, 0xB6 }, /* packet handshake */ + { BM_ESCAPE, 0xBA }, /* data escape */ + { 0x1B, 0x3B } /* escape */ +}; + +static int is_system; + +/* + * Setup serial interface + */ +static int +serial_bm_setup(struct ipmi_intf * intf) +{ + intf->session = malloc(sizeof(struct ipmi_session)); + if (intf->session == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + memset(intf->session, 0, sizeof(struct ipmi_session)); + + /* setup default LAN maximum request and response sizes */ + intf->max_request_data_size = SERIAL_BM_MAX_RQ_SIZE; + intf->max_response_data_size = SERIAL_BM_MAX_RS_SIZE; + return 0; +} + +/* + * Open serial interface + */ +static int +serial_bm_open(struct ipmi_intf * intf) +{ + struct termios ti; + unsigned int rate = 9600; + char *p; + int i; + + if (!intf->devfile) { + lprintf(LOG_ERR, "Serial device is not specified"); + return -1; + } + + is_system = 0; + + /* check if baud rate is specified */ + if ((p = strchr(intf->devfile, ':'))) { + char * pp; + + /* separate device name from baud rate */ + *p++ = '\0'; + + /* check for second colon */ + if ((pp = strchr(p, ':'))) { + /* this is needed to normally acquire baud rate */ + *pp++ = '\0'; + + /* check if it is a system interface */ + if (pp[0] == 'S' || pp[0] == 's') { + is_system = 1; + } + } + + if (str2uint(p, &rate)) { + lprintf(LOG_ERR, "Invalid baud rate specified\n"); + return -1; + } + } + + intf->fd = open(intf->devfile, O_RDWR | O_NONBLOCK, 0); + if (intf->fd < 0) { + lperror(LOG_ERR, "Could not open device at %s", intf->devfile); + return -1; + } + + for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) { + if (rates[i].baudrate == rate) { + break; + } + } + if (i >= sizeof(rates) / sizeof(rates[0])) { + lprintf(LOG_ERR, "Unsupported baud rate %i specified", rate); + return -1; + } + + tcgetattr(intf->fd, &ti); + + cfsetispeed(&ti, rates[i].baudinit); + cfsetospeed(&ti, rates[i].baudinit); + + /* 8N1 */ + ti.c_cflag &= ~PARENB; + ti.c_cflag &= ~CSTOPB; + ti.c_cflag &= ~CSIZE; + ti.c_cflag |= CS8; + + /* enable the receiver and set local mode */ + ti.c_cflag |= (CLOCAL | CREAD); + + /* no flow control */ + ti.c_cflag &= ~CRTSCTS; + ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP + | IXON | IXOFF | IXANY); +#ifdef IUCLC + /* Only disable uppercase-to-lowercase mapping on input for + platforms supporting the flag. */ + ti.c_iflag &= ~(IUCLC); +#endif + + + ti.c_oflag &= ~(OPOST); + ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH); + + /* set the new options for the port with flushing */ + tcsetattr(intf->fd, TCSAFLUSH, &ti); + + if (intf->session->timeout == 0) + intf->session->timeout = SERIAL_BM_TIMEOUT; + if (intf->session->retry == 0) + intf->session->retry = SERIAL_BM_RETRY_COUNT; + + intf->opened = 1; + + return 0; +} + +/* + * Close serial interface + */ +static void +serial_bm_close(struct ipmi_intf * intf) +{ + if (intf->opened) { + close(intf->fd); + intf->fd = -1; + } + + if (intf->session) { + free(intf->session); + intf->session = NULL; + } + + intf->opened = 0; +} + +/* + * Allocate sequence number for tracking + */ +static uint8_t +serial_bm_alloc_seq(void) +{ + static uint8_t seq = 0; + if (++seq == 64) { + seq = 0; + } + return seq; +} + +/* + * Flush the buffers + */ +static int +serial_bm_flush(struct ipmi_intf * intf) +{ +#if defined(TCFLSH) + return ioctl(intf->fd, TCFLSH, TCIOFLUSH); +#elif defined(TIOCFLUSH) + return ioctl(intf->fd, TIOCFLUSH); +#else +# error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)" +#endif +} + +/* + * Return escaped character for the given one + */ +static inline uint8_t +serial_bm_get_escaped_char(uint8_t c) +{ + int i; + + for (i = 0; i < 5; i++) { + if (characters[i].character == c) { + return characters[i].escape; + } + } + + return c; +} + +/* + * Return unescaped character for the given one + */ +static inline uint8_t +serial_bm_get_unescaped_char(uint8_t c) +{ + int i; + + for (i = 0; i < 5; i++) { + if (characters[i].escape == c) { + return characters[i].character; + } + } + + return c; +} + +/* + * Send message to serial port + */ +static int +serial_bm_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len) +{ + int i, size, tmp = 0; + uint8_t * buf, * data; + + if (verbose > 3) { + fprintf(stderr, "Sending request:\n"); + fprintf(stderr, " rsSA = 0x%x\n", msg[0]); + fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[1]); + fprintf(stderr, " rqSA = 0x%x\n", msg[3]); + fprintf(stderr, " rqSeq/rqLUN = 0x%x\n", msg[4]); + fprintf(stderr, " cmd = 0x%x\n", msg[5]); + if (msg_len > 7) { + fprintf(stderr, " data_len = %d\n", msg_len - 7); + fprintf(stderr, " data = %s\n", + buf2str(msg + 6, msg_len - 7)); + } + } + + if (verbose > 4) { + fprintf(stderr, "Message data:\n"); + fprintf(stderr, " %s\n", buf2str(msg, msg_len)); + } + + /* calculate escaped characters number */ + for (i = 0; i < msg_len; i++) { + if (serial_bm_get_escaped_char(msg[i]) != msg[i]) { + tmp++; + } + } + + /* calculate required buffer size */ + size = msg_len + tmp + 2; + + /* allocate buffer for output data */ + buf = data = (uint8_t *) alloca(size); + + if (!buf) { + lperror(LOG_ERR, "ipmitool: alloca error"); + return -1; + } + + /* start character */ + *buf++ = 0xA0; + + for (i = 0; i < msg_len; i++) { + tmp = serial_bm_get_escaped_char(msg[i]); + if (tmp != msg[i]) { + *buf++ = 0xAA; + } + + *buf++ = tmp; + } + + /* stop character */ + *buf++ = 0xA5; + + if (verbose > 5) { + fprintf(stderr, "Sent serial data:\n %s\n", buf2str(data, size)); + } + + /* write data to serial port */ + tmp = write(intf->fd, data, size); + if (tmp <= 0) { + lperror(LOG_ERR, "ipmitool: write error"); + return -1; + } + + return 0; +} + +/* + * This function waits for incoming data + */ +static int +serial_bm_wait_for_data(struct ipmi_intf * intf) +{ + int n; + struct pollfd pfd; + + pfd.fd = intf->fd; + pfd.events = POLLIN; + pfd.revents = 0; + + n = poll(&pfd, 1, intf->session->timeout*1000); + if (n < 0) { + lperror(LOG_ERR, "Poll for serial data failed"); + return -1; + } else if (!n) { + return -1; + } + return 0; +} + +/* + * This function parses incoming data in basic mode format to IPMB message + */ +static int +serial_bm_parse_buffer(const uint8_t * data, int data_len, + struct serial_bm_parse_ctx * ctx) +{ + int i, tmp; + + for (i = 0; i < data_len; i++) { + /* check for start of new message */ + if (data[i] == BM_START) { + ctx->state = MSG_IN_PROGRESS; + ctx->escape = 0; + ctx->msg_len = 0; + /* check if message is not started */ + } else if (ctx->state != MSG_IN_PROGRESS) { + /* skip character */ + continue; + /* continue escape sequence */ + } else if (ctx->escape) { + /* get original character */ + tmp = serial_bm_get_unescaped_char(data[i]); + + /* check if not special character */ + if (tmp == data[i]) { + lprintf(LOG_ERR, "ipmitool: bad response"); + /* reset message state */ + ctx->state = MSG_NONE; + continue; + } + + /* check message length */ + if (ctx->msg_len >= ctx->max_len) { + lprintf(LOG_ERR, "ipmitool: response is too long"); + /* reset message state */ + ctx->state = MSG_NONE; + continue; + } + + /* add parsed character */ + ctx->msg[ctx->msg_len++] = tmp; + + /* clear escape flag */ + ctx->escape = 0; + /* check for escape character */ + } else if (data[i] == BM_ESCAPE) { + ctx->escape = 1; + continue; + /* check for stop character */ + } else if (data[i] == BM_STOP) { + ctx->state = MSG_DONE; + return i + 1; + /* check for packet handshake character */ + } else if (data[i] == BM_HANDSHAKE) { + /* just skip it */ + continue; + } else { + /* check message length */ + if (ctx->msg_len >= ctx->max_len) { + lprintf(LOG_ERR, "ipmitool: response is too long"); + return -1; + } + + /* add parsed character */ + ctx->msg[ctx->msg_len++] = data[i]; + } + } + + /* return number of parsed characters */ + return i; +} + +/* + * Read and parse data from serial port + */ +static int +serial_bm_recv_msg(struct ipmi_intf * intf, + struct serial_bm_recv_ctx * recv_ctx, + uint8_t * msg_data, size_t msg_len) +{ + struct serial_bm_parse_ctx parse_ctx; + int rv; + + parse_ctx.state = MSG_NONE; + parse_ctx.msg = msg_data; + parse_ctx.max_len = msg_len; + + do { + /* wait for data in the port */ + if (serial_bm_wait_for_data(intf)) { + return 0; + } + + /* read data into buffer */ + rv = read(intf->fd, recv_ctx->buffer + recv_ctx->buffer_size, + recv_ctx->max_buffer_size - recv_ctx->buffer_size); + + if (rv < 0) { + lperror(LOG_ERR, "ipmitool: read error"); + return -1; + } + + if (verbose > 5) { + fprintf(stderr, "Received serial data:\n %s\n", + buf2str(recv_ctx->buffer + recv_ctx->buffer_size, rv)); + } + + /* increment buffer size */ + recv_ctx->buffer_size += rv; + + /* parse buffer */ + rv = serial_bm_parse_buffer(recv_ctx->buffer, + recv_ctx->buffer_size, &parse_ctx); + + if (rv < recv_ctx->buffer_size) { + /* move non-parsed part of the buffer to the beginning */ + memmove(recv_ctx->buffer, recv_ctx->buffer + rv, + recv_ctx->buffer_size - rv); + } + + /* decrement buffer size */ + recv_ctx->buffer_size -= rv; + } while (parse_ctx.state != MSG_DONE); + + if (verbose > 4) { + printf("Received message:\n %s\n", + buf2str(msg_data, parse_ctx.msg_len)); + } + + /* received a message */ + return parse_ctx.msg_len; +} + +/* + * Build IPMB message to be transmitted + */ +static int +serial_bm_build_msg(const struct ipmi_intf * intf, + const struct ipmi_rq * req, uint8_t * msg, size_t max_len, + struct serial_bm_request_ctx * ctx, int * msg_len + ) +{ + uint8_t * data = msg, seq; + struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg; + struct ipmi_send_message_rq * inner_rq = NULL, * outer_rq = NULL; + int bridging_level; + + /* acquire bridging level */ + if (intf->target_addr && intf->target_addr != intf->my_addr) { + if (intf->transit_addr != 0) { + bridging_level = 2; + } else { + bridging_level = 1; + } + } else { + bridging_level = 0; + } + + /* check overall packet length */ + if(req->msg.data_len + 7 + bridging_level * 8 > max_len) { + lprintf(LOG_ERR, "ipmitool: Message data is too long"); + return -1; + } + + /* allocate new sequence number */ + seq = serial_bm_alloc_seq() << 2; + + if (bridging_level) { + /* compose send message request */ + hdr->netFn = 0x18; + hdr->cmd = 0x34; + + /* set pointer to send message request data */ + outer_rq = (struct ipmi_send_message_rq *) (hdr + 1); + + /* compose the outer send message request */ + if (bridging_level == 2) { + outer_rq->channel = intf->transit_channel | 0x40; + outer_rq->msg.rsSA = intf->transit_addr; + outer_rq->msg.netFn = 0x18; + outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn); + outer_rq->msg.rqSA = intf->my_addr; + outer_rq->msg.rqSeq = seq; + outer_rq->msg.cmd = 0x34; + + /* inner send message request is further */ + inner_rq = (outer_rq + 1); + } else { + /* there is only outer send message reuest */ + inner_rq = outer_rq; + } + + /* compose the inner send message request */ + inner_rq->channel = intf->target_channel | 0x40; + inner_rq->msg.rsSA = intf->target_addr; + inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun; + inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn); + inner_rq->msg.rqSA = intf->my_addr; + inner_rq->msg.rqSeq = seq; + inner_rq->msg.cmd = req->msg.cmd; + + /* check if interface is the system one */ + if (is_system) { + /* need response to LUN 2 */ + outer_rq->msg.rqSeq |= 2; + + /* do not track response */ + outer_rq->channel &= ~0x40; + + /* restore BMC SA if bridging not to primary IPMB channel */ + if (outer_rq->channel) { + outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR; + } + } + + /* fill-in the second context */ + ctx[1].rsSA = outer_rq->msg.rsSA; + ctx[1].netFn = outer_rq->msg.netFn; + ctx[1].rqSA = outer_rq->msg.rqSA; + ctx[1].rqSeq = outer_rq->msg.rqSeq; + ctx[1].cmd = outer_rq->msg.cmd; + + /* move write pointer */ + msg = (uint8_t *)(inner_rq + 1); + } else { + /* compose direct request */ + hdr->netFn = (req->msg.netfn << 2) | req->msg.lun; + hdr->cmd = req->msg.cmd; + + /* move write pointer */ + msg = (uint8_t *)(hdr + 1); + } + + /* fill-in the rest header fields */ + hdr->rsSA = IPMI_BMC_SLAVE_ADDR; + hdr->csum1 = -(hdr->rsSA + hdr->netFn); + hdr->rqSA = IPMI_REMOTE_SWID; + hdr->rqSeq = seq; + + /* fill-in the first context */ + ctx[0].rsSA = hdr->rsSA; + ctx[0].netFn = hdr->netFn; + ctx[0].rqSA = hdr->rqSA; + ctx[0].rqSeq = hdr->rqSeq; + ctx[0].cmd = hdr->cmd; + + /* write request data */ + memcpy(msg, req->msg.data, req->msg.data_len); + + /* move write pointer */ + msg += req->msg.data_len; + + if (bridging_level) { + /* write inner message checksum */ + *msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3); + + /* check for double bridging */ + if (bridging_level == 2) { + /* write outer message checksum */ + *msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4); + } + + /* write overall message checksum */ + *msg++ = ipmi_csum(&hdr->rqSA, 4); + } else { + /* write overall message checksum */ + *msg++ = ipmi_csum(&hdr->rqSA, req->msg.data_len + 3); + } + + /* save message length */ + *msg_len = msg - data; + + /* return bridging level */ + return bridging_level; +} + +/* + * Wait for request response + */ +static int +serial_bm_wait_response(struct ipmi_intf * intf, + struct serial_bm_request_ctx * req_ctx, struct serial_bm_recv_ctx * read_ctx, + uint8_t * msg, size_t max_len) +{ + struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg; + int msg_len, netFn, rqSeq; + + /* receive and match message */ + while ((msg_len = serial_bm_recv_msg(intf, read_ctx, msg, max_len)) > 0) { + /* validate message size */ + if (msg_len < 8) { + lprintf(LOG_ERR, "ipmitool: response is too short"); + continue; + } + + /* validate checksum 1 */ + if (ipmi_csum(msg, 3)) { + lprintf(LOG_ERR, "ipmitool: bad checksum 1"); + continue; + } + + /* validate checksum 2 */ + if (ipmi_csum(msg + 3, msg_len - 3)) { + lprintf(LOG_ERR, "ipmitool: bad checksum 2"); + continue; + } + + /* swap requester and responder LUNs */ + netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3); + rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3); + + /* check for the waited response */ + if (hdr->rsSA == req_ctx->rqSA + && hdr->netFn == netFn + && hdr->rqSA == req_ctx->rsSA + && hdr->rqSeq == rqSeq + && hdr->cmd == req_ctx->cmd) { + /* check if something new has been parsed */ + if (verbose > 3) { + fprintf(stderr, "Got response:\n"); + fprintf(stderr, " rsSA = 0x%x\n", msg[0]); + fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[1]); + fprintf(stderr, " rqSA = 0x%x\n", msg[3]); + fprintf(stderr, " rqSeq/rqLUN = 0x%x\n", msg[4]); + fprintf(stderr, " cmd = 0x%x\n", msg[5]); + fprintf(stderr, " completion code = 0x%x\n", msg[6]); + if (msg_len > 8) { + fprintf(stderr, " data_len = %d\n", msg_len - 8); + fprintf(stderr, " data = %s\n", + buf2str(msg + 7, msg_len - 8)); + } + } + + /* copy only completion and response data */ + memmove(msg, hdr + 1, msg_len - sizeof (*hdr) - 1); + + /* update message length */ + msg_len -= sizeof (*hdr) + 1; + + /* the waited one */ + break; + } + } + + return msg_len; +} + +/* + * Get message from receive message queue + */ +static int +serial_bm_get_message(struct ipmi_intf * intf, + struct serial_bm_request_ctx * req_ctx, + struct serial_bm_recv_ctx * read_ctx, + uint8_t * msg, size_t max_len) +{ + uint8_t data[SERIAL_BM_MAX_MSG_SIZE]; + struct serial_bm_request_ctx tmp_ctx; + struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data; + struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) data; + clock_t start, tm; + int rv, netFn, rqSeq; + + start = clock(); + + do { + /* fill-in request context */ + tmp_ctx.rsSA = IPMI_BMC_SLAVE_ADDR; + tmp_ctx.netFn = 0x18; + tmp_ctx.rqSA = IPMI_REMOTE_SWID; + tmp_ctx.rqSeq = serial_bm_alloc_seq() << 2; + tmp_ctx.cmd = 0x33; + + /* fill-in request data */ + hdr->rsSA = tmp_ctx.rsSA; + hdr->netFn = tmp_ctx.netFn; + hdr->csum1 = ipmi_csum(data, 2); + hdr->rqSA = tmp_ctx.rqSA; + hdr->rqSeq = tmp_ctx.rqSeq; + hdr->cmd = tmp_ctx.cmd; + hdr->data[0] = ipmi_csum(&hdr->rqSA, 3); + + /* send request */ + serial_bm_flush(intf); + serial_bm_send_msg(intf, data, 7); + + /* wait for response */ + rv = serial_bm_wait_response(intf, &tmp_ctx, read_ctx, + data, sizeof (data)); + + /* check for IO error or timeout */ + if (rv <= 0) { + return rv; + } + + /* check completion code */ + if (rp->completion == 0) { + /* swap requester and responder LUNs */ + netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3); + rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3); + + /* check for the waited response */ + if (rp->netFn == netFn + && rp->rsSA == req_ctx->rsSA + && rp->rqSeq == rqSeq + && rp->cmd == req_ctx->cmd) { + /* copy the rest of message */ + memcpy(msg, rp->data, rv - sizeof (*rp) - 1); + return rv - sizeof (*rp) - 1; + } + } else if (rp->completion != 0x80) { + return 0; + } + + tm = clock() - start; + + tm /= CLOCKS_PER_SEC; + } while (tm < intf->session->timeout); + + return 0; +} + +static struct ipmi_rs * +serial_bm_send_request(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + static struct ipmi_rs rsp; + uint8_t msg[SERIAL_BM_MAX_MSG_SIZE], * resp = msg; + struct serial_bm_request_ctx req_ctx[3]; + struct serial_bm_recv_ctx read_ctx; + int retry, rv, msg_len, bridging_level; + + if (!intf->opened && intf->open && intf->open(intf) < 0) { + return NULL; + } + + /* reset receive context */ + read_ctx.buffer_size = 0; + read_ctx.max_buffer_size = SERIAL_BM_MAX_BUFFER_SIZE; + + /* Send the message and receive the answer */ + for (retry = 0; retry < intf->session->retry; retry++) { + /* build output message */ + bridging_level = serial_bm_build_msg(intf, req, msg, + sizeof (msg), req_ctx, &msg_len); + if (msg_len < 0) { + return NULL; + } + + /* send request */ + serial_bm_flush(intf); + serial_bm_send_msg(intf, msg, msg_len); + + /* wait for response */ + rv = serial_bm_wait_response(intf, &req_ctx[0], + &read_ctx, msg, sizeof (msg)); + + /* check for IO error */ + if (rv < 0) { + return NULL; + } + + /* check for timeout */ + if (rv == 0) { + continue; + } + + /* check for bridging */ + if (bridging_level && msg[0] == 0) { + /* in the case of payload interface we check receive message queue */ + if (is_system) { + /* check message flags */ + rv = serial_bm_get_message(intf, &req_ctx[1], + &read_ctx, msg, sizeof (msg)); + + /* check for IO error */ + if (rv < 0) { + return NULL; + } + + /* check for timeout */ + if (rv == 0) { + continue; + } + /* check if response for inner request is not encapsulated */ + } else if (rv == 1) { + /* wait for response for inner request */ + rv = serial_bm_wait_response(intf, &req_ctx[0], + &read_ctx, msg, sizeof (msg)); + + /* check for IO error */ + if (rv < 0) { + return NULL; + } + + /* check for timeout */ + if (rv == 0) { + continue; + } + } else { + /* skip outer level header */ + resp = msg + 7; + /* decrement response size */ + rv -= 8; + } + + /* check response size */ + if (resp[0] == 0 && bridging_level == 2 && rv < 8) { + lprintf(LOG_ERR, "ipmitool: Message response is too short"); + /* invalid message length */ + return NULL; + } + } + + /* check for double bridging */ + if (bridging_level == 2 && resp[0] == 0) { + /* get completion code */ + rsp.ccode = resp[7]; + rsp.data_len = rv - 9; + memcpy(rsp.data, resp + 8, rsp.data_len); + } else { + rsp.ccode = resp[0]; + rsp.data_len = rv - 1; + memcpy(rsp.data, resp + 1, rsp.data_len); + } + + /* return response */ + return &rsp; + } + + /* no valid response */ + return NULL; +} + +int +serial_bm_set_my_addr(struct ipmi_intf * intf, uint8_t addr) +{ + intf->my_addr = addr; + return 0; +} + +/* + * Serial BM interface + */ +struct ipmi_intf ipmi_serial_bm_intf = { + name: "serial-basic", + desc: "Serial Interface, Basic Mode", + setup: serial_bm_setup, + open: serial_bm_open, + close: serial_bm_close, + sendrecv: serial_bm_send_request, + set_my_addr:serial_bm_set_my_addr +}; diff --git a/src/plugins/serial/serial_terminal.c b/src/plugins/serial/serial_terminal.c new file mode 100644 index 0000000..41d3753 --- /dev/null +++ b/src/plugins/serial/serial_terminal.c @@ -0,0 +1,919 @@ +/* + * Copyright (c) 2007-2012 Pigeon Point Systems. 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 Pigeon Point Systems nor 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. + * PIGEON POINT SYSTEMS ("PPS") 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 + * PPS 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 PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +/* Serial Interface, Terminal Mode plugin. */ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/poll.h> +#include <termios.h> + +#include <ipmitool/ipmi.h> +#include <ipmitool/ipmi_intf.h> +#include <ipmitool/helper.h> +#include <ipmitool/log.h> + +#if defined(HAVE_CONFIG_H) +# include <config.h> +#endif + +#define IPMI_SERIAL_TIMEOUT 5 +#define IPMI_SERIAL_RETRY 5 +#define IPMI_SERIAL_MAX_RESPONSE 256 + +/* + * Terminal Mode interface is required to support 40 byte transactions. + */ +#define IPMI_SERIAL_MAX_RQ_SIZE 37 /* 40 - 3 */ +#define IPMI_SERIAL_MAX_RS_SIZE 36 /* 40 - 4 */ + +/* + * IPMB message header + */ +struct ipmb_msg_hdr { + unsigned char rsSA; + unsigned char netFn; /* NET FN | RS LUN */ + unsigned char csum1; + unsigned char rqSA; + unsigned char rqSeq; /* RQ SEQ | RQ LUN */ + unsigned char cmd; + unsigned char data[0]; +}; + +/* + * Send Message command request for IPMB-format + */ +struct ipmi_send_message_rq { + unsigned char channel; + struct ipmb_msg_hdr msg; +}; + +/* + * Get Message command response for IPMB-format + */ +struct ipmi_get_message_rp { + unsigned char completion; + unsigned char channel; + unsigned char netFn; + unsigned char csum1; + unsigned char rsSA; + unsigned char rqSeq; + unsigned char cmd; + unsigned char data[0]; +}; + +/* + * Terminal mode message header + */ +struct serial_term_hdr { + unsigned char netFn; + unsigned char seq; + unsigned char cmd; +}; + +/* + * Sending context + */ +struct serial_term_request_ctx { + uint8_t netFn; + uint8_t sa; + uint8_t seq; + uint8_t cmd; +}; + +/* + * Table of supported baud rates + */ +static const struct { + int baudinit; + int baudrate; +} rates[] = { + { B2400, 2400 }, + { B9600, 9600 }, + { B19200, 19200 }, + { B38400, 38400 }, + { B57600, 57600 }, + { B115200, 115200 }, + { B230400, 230400 }, +#ifdef B460800 + { B460800, 460800 }, +#endif +}; + +static int is_system; + +static int +ipmi_serial_term_open(struct ipmi_intf * intf) +{ + struct termios ti; + unsigned int rate = 9600; + char *p; + int i; + + if (!intf->devfile) { + lprintf(LOG_ERR, "Serial device is not specified"); + return -1; + } + + is_system = 0; + + /* check if baud rate is specified */ + if ((p = strchr(intf->devfile, ':'))) { + char * pp; + + /* separate device name from baud rate */ + *p++ = '\0'; + + /* check for second colon */ + if ((pp = strchr(p, ':'))) { + /* this is needed to normally acquire baud rate */ + *pp++ = '\0'; + + /* check if it is a system interface */ + if (pp[0] == 'S' || pp[0] == 's') { + is_system = 1; + } + } + + if (str2uint(p, &rate)) { + lprintf(LOG_ERR, "Invalid baud rate specified\n"); + return -1; + } + } + + intf->fd = open(intf->devfile, O_RDWR | O_NONBLOCK, 0); + if (intf->fd < 0) { + lperror(LOG_ERR, "Could not open device at %s", intf->devfile); + return -1; + } + + for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) { + if (rates[i].baudrate == rate) { + break; + } + } + if (i >= sizeof(rates) / sizeof(rates[0])) { + lprintf(LOG_ERR, "Unsupported baud rate %i specified", rate); + return -1; + } + + tcgetattr(intf->fd, &ti); + + cfsetispeed(&ti, rates[i].baudinit); + cfsetospeed(&ti, rates[i].baudinit); + + /* 8N1 */ + ti.c_cflag &= ~PARENB; + ti.c_cflag &= ~CSTOPB; + ti.c_cflag &= ~CSIZE; + ti.c_cflag |= CS8; + + /* enable the receiver and set local mode */ + ti.c_cflag |= (CLOCAL | CREAD); + + /* no flow control */ + ti.c_cflag &= ~CRTSCTS; + ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP + | IXON | IXOFF | IXANY); +#ifdef IUCLC + /* Only disable uppercase-to-lowercase mapping on input for + platforms supporting the flag. */ + ti.c_iflag &= ~(IUCLC); +#endif + + ti.c_oflag &= ~(OPOST); + ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH); + + /* set the new options for the port with flushing */ + tcsetattr(intf->fd, TCSAFLUSH, &ti); + + if (intf->session->timeout == 0) + intf->session->timeout = IPMI_SERIAL_TIMEOUT; + if (intf->session->retry == 0) + intf->session->retry = IPMI_SERIAL_RETRY; + + intf->opened = 1; + + return 0; +} + +static void +ipmi_serial_term_close(struct ipmi_intf * intf) +{ + if (intf->opened) { + close(intf->fd); + intf->fd = -1; + } + + if (intf->session) { + free(intf->session); + intf->session = NULL; + } + + intf->opened = 0; +} + +/* + * This function waits for incoming byte during timeout (ms). + */ +static int +serial_wait_for_data(struct ipmi_intf * intf) +{ + int n; + struct pollfd pfd; + + pfd.fd = intf->fd; + pfd.events = POLLIN; + pfd.revents = 0; + + n = poll(&pfd, 1, intf->session->timeout*1000); + if (n < 0) { + lperror(LOG_ERR, "Poll for serial data failed"); + return -1; + } else if (!n) { + return -1; + } + return 0; +} + +/* + * Read a line from serial port + * Returns > 0 if there is a line, < 0 on error or timeout + */ +static int +serial_read_line(struct ipmi_intf * intf, char *str, int len) +{ + int rv, i; + + *str = 0; + i = 0; + while (i < len) { + if (serial_wait_for_data(intf)) { + return -1; + } + rv = read(intf->fd, str + i, 1); + if (rv < 0) { + return -1; + } else if (!rv) { + lperror(LOG_ERR, "Serial read failed: %s", strerror(errno)); + return -1; + } + if (str[i] == '\n' || str[i] == '\r') { + if (verbose > 4) { + char c = str[i]; + str[i] = '\0'; + fprintf(stderr, "Received data: %s\n", str); + str[i] = c; + } + return i + 1; + } else { + i++; + } + } + + lprintf(LOG_ERR, "Serial data is too long"); + return -1; +} + +/* + * Send zero-terminated string to serial port + * Returns the string length or negative error code + */ +static int +serial_write_line(struct ipmi_intf * intf, const char *str) +{ + int rv, cnt = 0; + int cb = strlen(str); + + while (cnt < cb) { + rv = write(intf->fd, str + cnt, cb - cnt); + if (rv < 0) { + return -1; + } else if (rv == 0) { + return -1; + } + cnt += rv; + } + + return cnt; +} + +/* + * Flush the buffers + */ +static int +serial_flush(struct ipmi_intf * intf) +{ +#if defined(TCFLSH) + return ioctl(intf->fd, TCFLSH, TCIOFLUSH); +#elif defined(TIOCFLUSH) + return ioctl(intf->fd, TIOCFLUSH); +#else +# error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)" +#endif + +} + +/* + * Receive IPMI response from the device + * Len: buffer size + * Returns: -1 or response lenth on success + */ +static int +recv_response(struct ipmi_intf * intf, unsigned char *data, int len) +{ + char hex_rs[IPMI_SERIAL_MAX_RESPONSE * 3]; + int i, j, resp_len = 0; + unsigned long rv; + char *p, *pp; + char ch, str_hex[3]; + + p = hex_rs; + while (1) { + if ((rv = serial_read_line(intf, p, sizeof(hex_rs) - resp_len)) < 0) { + /* error */ + return -1; + } + p += rv; + resp_len += rv; + if (*(p - 2) == ']' && (*(p - 1) == '\n' || *(p - 1) == '\r')) { + *p = 0; + break; + } + } + + p = strrchr(hex_rs, '['); + if (!p) { + lprintf(LOG_ERR, "Serial response is invalid"); + return -1; + } + + p++; + pp = strchr(p, ']'); + if (!pp) { + lprintf(LOG_ERR, "Serial response is invalid"); + return -1; + } + *pp = 0; + + /* was it an error? */ + if (strncmp(p, "ERR ", 4) == 0) { + serial_write_line(intf, "\r\r\r\r"); + sleep(1); + serial_flush(intf); + errno = 0; + rv = strtoul(p + 4, &p, 16); + if ((rv && rv < 0x100 && *p == '\0') + || (rv == 0 && !errno)) { + /* The message didn't get it through. The upper + level will have to re-send */ + return 0; + } else { + lprintf(LOG_ERR, "Serial response is invalid"); + return -1; + } + } + + /* this is needed for correct string to long conversion */ + str_hex[2] = 0; + + /* parse the response */ + i = 0; + j = 0; + while (*p) { + if (i >= len) { + lprintf(LOG_ERR, "Serial response is too long(%d, %d)", i, len); + return -1; + } + ch = *(p++); + if (isxdigit(ch)) { + str_hex[j++] = ch; + } else { + if (j == 1 || !isspace(ch)) { + lprintf(LOG_ERR, "Serial response is invalid"); + return -1; + } + } + if (j == 2) { + unsigned long tmp; + errno = 0; + /* parse the hex number */ + tmp = strtoul(str_hex, NULL, 16); + if ( tmp > 0xFF || ( !tmp && errno ) ) { + lprintf(LOG_ERR, "Serial response is invalid"); + return -1; + } + data[i++] = tmp; + j = 0; + } + } + + return i; +} + +/* + * Allocate sequence number for tracking + */ +static uint8_t +serial_term_alloc_seq(void) +{ + static uint8_t seq = 0; + if (++seq == 64) { + seq = 0; + } + return seq; +} + +/* + * Build IPMB message to be transmitted + */ +static int +serial_term_build_msg(const struct ipmi_intf * intf, + const struct ipmi_rq * req, uint8_t * msg, size_t max_len, + struct serial_term_request_ctx * ctx, int * msg_len) +{ + uint8_t * data = msg, seq; + struct serial_term_hdr * term_hdr = (struct serial_term_hdr *) msg; + struct ipmi_send_message_rq * outer_rq = NULL; + struct ipmi_send_message_rq * inner_rq = NULL; + int bridging_level; + + /* acquire bridging level */ + if (intf->target_addr && intf->target_addr != intf->my_addr) { + if (intf->transit_addr != 0) { + bridging_level = 2; + } else { + bridging_level = 1; + } + } else { + bridging_level = 0; + } + + /* check overall packet length */ + if(req->msg.data_len + 3 + bridging_level * 8 > max_len) { + lprintf(LOG_ERR, "ipmitool: Message data is too long"); + return -1; + } + + /* allocate new sequence number */ + seq = serial_term_alloc_seq() << 2; + + /* check for bridging */ + if (bridging_level) { + /* compose terminal message header */ + term_hdr->netFn = 0x18; + term_hdr->seq = seq; + term_hdr->cmd = 0x34; + + /* set pointer to send message request data */ + outer_rq = (struct ipmi_send_message_rq *) (term_hdr + 1); + + if (bridging_level == 2) { + /* compose the outer send message request */ + outer_rq->channel = intf->transit_channel | 0x40; + outer_rq->msg.rsSA = intf->transit_addr; + outer_rq->msg.netFn = 0x18; + outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn); + outer_rq->msg.rqSA = intf->my_addr; + outer_rq->msg.rqSeq = seq; + outer_rq->msg.cmd = 0x34; + + /* inner request is further */ + inner_rq = (outer_rq + 1); + } else { + /* there is only one header */ + inner_rq = outer_rq; + } + + /* compose the inner send message request */ + inner_rq->channel = intf->target_channel | 0x40; + inner_rq->msg.rsSA = intf->target_addr; + inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun; + inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn); + inner_rq->msg.rqSA = intf->my_addr; + inner_rq->msg.rqSeq = seq; + inner_rq->msg.cmd = req->msg.cmd; + + /* check if interface is the system one */ + if (is_system) { + /* need response to LUN 2 */ + outer_rq->msg.rqSeq |= 2; + + /* do not track response */ + outer_rq->channel &= ~0x40; + + /* restore BMC SA if bridging not to primary IPMB channel */ + if (outer_rq->channel) { + outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR; + } + } + + /* fill the second context */ + ctx[1].netFn = outer_rq->msg.netFn; + ctx[1].sa = outer_rq->msg.rsSA; + ctx[1].seq = outer_rq->msg.rqSeq; + ctx[1].cmd = outer_rq->msg.cmd; + + /* move write pointer */ + msg = (uint8_t *)(inner_rq + 1); + } else { + /* compose terminal message header */ + term_hdr->netFn = (req->msg.netfn << 2) | req->msg.lun; + term_hdr->seq = seq; + term_hdr->cmd = req->msg.cmd; + + /* move write pointer */ + msg = (uint8_t *)(term_hdr + 1); + } + + /* fill the first context */ + ctx[0].netFn = term_hdr->netFn; + ctx[0].seq = term_hdr->seq; + ctx[0].cmd = term_hdr->cmd; + + /* write request data */ + memcpy(msg, req->msg.data, req->msg.data_len); + + /* move write pointer */ + msg += req->msg.data_len; + + if (bridging_level) { + /* write inner message checksum */ + *msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3); + + /* check for double bridging */ + if (bridging_level == 2) { + /* write outer message checksum */ + *msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4); + } + } + + + /* save message length */ + *msg_len = msg - data; + + /* return bridging level */ + return bridging_level; +} + +/* + * Send message to serial port + */ +static int +serial_term_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len) +{ + int i, size, tmp = 0; + uint8_t * buf, * data; + + if (verbose > 3) { + fprintf(stderr, "Sending request:\n"); + fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[0]); + fprintf(stderr, " rqSeq = 0x%x\n", msg[1]); + fprintf(stderr, " cmd = 0x%x\n", msg[2]); + if (msg_len > 7) { + fprintf(stderr, " data_len = %d\n", msg_len - 3); + fprintf(stderr, " data = %s\n", + buf2str(msg + 3, msg_len - 3)); + } + } + + if (verbose > 4) { + fprintf(stderr, "Message data:\n"); + fprintf(stderr, " %s\n", buf2str(msg, msg_len)); + } + + /* calculate required buffer size */ + size = msg_len * 2 + 4; + + /* allocate buffer for output data */ + buf = data = (uint8_t *) alloca(size); + + if (!buf) { + lperror(LOG_ERR, "ipmitool: alloca error"); + return -1; + } + + /* start character */ + *buf++ = '['; + + /* body */ + for (i = 0; i < msg_len; i++) { + buf += sprintf( buf, "%02x", msg[i]); + } + + /* stop character */ + *buf++ = ']'; + + /* carriage return */ + *buf++ = '\r'; + + /* line feed */ + *buf++ = '\n'; + + /* write data to serial port */ + tmp = write(intf->fd, data, size); + if (tmp <= 0) { + lperror(LOG_ERR, "ipmitool: write error"); + return -1; + } + + return 0; +} + +/* + * Wait for request response + */ +static int +serial_term_wait_response(struct ipmi_intf * intf, + struct serial_term_request_ctx * req_ctx, + uint8_t * msg, size_t max_len) +{ + struct serial_term_hdr * hdr = (struct serial_term_hdr *) msg; + int msg_len; + + /* wait for response(s) */ + do { + /* receive message */ + msg_len = recv_response(intf, msg, max_len); + + /* check if valid message received */ + if (msg_len > 0) { + /* validate message size */ + if (msg_len < 4) { + /* either bad response or non-related message */ + continue; + } + + /* check for the waited response */ + if (hdr->netFn == (req_ctx->netFn|4) + && (hdr->seq & ~3) == req_ctx->seq + && hdr->cmd == req_ctx->cmd) { + /* check if something new has been parsed */ + if (verbose > 3) { + fprintf(stderr, "Got response:\n"); + fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[0]); + fprintf(stderr, " rqSeq/Bridge = 0x%x\n", msg[1]); + fprintf(stderr, " cmd = 0x%x\n", msg[2]); + fprintf(stderr, " completion code = 0x%x\n", msg[3]); + if (msg_len > 8) { + fprintf(stderr, " data_len = %d\n", + msg_len - 4); + fprintf(stderr, " data = %s\n", + buf2str(msg + 4, msg_len - 4)); + } + } + + /* move to start from completion code */ + memmove(msg, hdr + 1, msg_len - sizeof (*hdr)); + + /* the waited one */ + return msg_len - sizeof (*hdr); + } + } + } while (msg_len > 0); + + return 0; +} + +/* + * Get message from receive message queue + */ +static int +serial_term_get_message(struct ipmi_intf * intf, + struct serial_term_request_ctx * req_ctx, + uint8_t * msg, size_t max_len) +{ + uint8_t data[IPMI_SERIAL_MAX_RESPONSE]; + struct serial_term_request_ctx tmp_ctx; + struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data; + struct serial_term_hdr hdr; + clock_t start, tm; + int rv, netFn, rqSeq; + + start = clock(); + + do { + /* fill-in request context */ + tmp_ctx.netFn = 0x18; + tmp_ctx.seq = serial_term_alloc_seq() << 2; + tmp_ctx.cmd = 0x33; + + /* fill-in request data */ + hdr.netFn = tmp_ctx.netFn; + hdr.seq = tmp_ctx.seq; + hdr.cmd = tmp_ctx.cmd; + + /* send request */ + serial_flush(intf); + serial_term_send_msg(intf, (uint8_t *) &hdr, 3); + + /* wait for response */ + rv = serial_term_wait_response(intf, &tmp_ctx, data, sizeof (data)); + + /* check for IO error or timeout */ + if (rv <= 0) { + return rv; + } + + netFn = (req_ctx->netFn & ~3)|(req_ctx->seq & 3)|4; + rqSeq = req_ctx->seq & ~3; + + /* check completion code */ + if (rp->completion == 0) { + /* check for the waited response */ + if (rp->netFn == netFn + && rp->rsSA == req_ctx->sa + && rp->rqSeq == rqSeq + && rp->cmd == req_ctx->cmd) { + /* copy the rest of message */ + memcpy(msg, rp + 1, rv - sizeof (*rp) - 1); + return rv - sizeof (*rp) - 1; + } + } else if (rp->completion != 0x80) { + return 0; + } + + tm = clock() - start; + + tm /= CLOCKS_PER_SEC; + } while (tm < intf->session->timeout); + + return 0; +} + +static struct ipmi_rs * +ipmi_serial_term_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) +{ + static struct ipmi_rs rsp; + uint8_t msg[IPMI_SERIAL_MAX_RESPONSE], * resp = msg; + struct serial_term_request_ctx req_ctx[2]; + int retry, rv, msg_len, bridging_level; + + if (!intf->opened && intf->open && intf->open(intf) < 0) { + return NULL; + } + + /* Send the message and receive the answer */ + for (retry = 0; retry < intf->session->retry; retry++) { + /* build output message */ + bridging_level = serial_term_build_msg(intf, req, msg, + sizeof (msg), req_ctx, &msg_len); + if (msg_len < 0) { + return NULL; + } + + /* send request */ + serial_flush(intf); + serial_term_send_msg(intf, msg, msg_len); + + /* wait for response */ + rv = serial_term_wait_response(intf, &req_ctx[0], msg, sizeof (msg)); + + /* check for IO error */ + if (rv < 0) { + return NULL; + } + + /* check for timeout */ + if (rv == 0) { + continue; + } + + /* check for bridging */ + if (bridging_level && msg[0] == 0) { + /* in the case of payload interface we check receive message queue */ + if (is_system) { + /* check message flags */ + rv = serial_term_get_message(intf, &req_ctx[1], + msg, sizeof (msg)); + + /* check for IO error */ + if (rv < 0) { + return NULL; + } + + /* check for timeout */ + if (rv == 0) { + continue; + } + /* check if response for inner request is not encapsulated */ + } else if (rv == 1) { + /* wait for response for inner request */ + rv = serial_term_wait_response(intf, &req_ctx[1], + msg, sizeof (msg)); + + /* check for IO error */ + if (rv < 0) { + return NULL; + } + + /* check for timeout */ + if (rv == 0) { + continue; + } + } else { + /* skip outer level header */ + resp = msg + sizeof (struct ipmb_msg_hdr) + 1; + /* decrement response size */ + rv -= + sizeof (struct ipmb_msg_hdr) + 2; + } + + /* check response size */ + if (resp[0] == 0 && bridging_level == 2 && rv < 8) { + lprintf(LOG_ERR, "ipmitool: Message response is too short"); + /* invalid message length */ + return NULL; + } + } + + /* check for double bridging */ + if (bridging_level == 2 && resp[0] == 0) { + /* get completion code */ + rsp.ccode = resp[7]; + rsp.data_len = rv - 9; + memcpy(rsp.data, resp + 8, rsp.data_len); + } else { + rsp.ccode = resp[0]; + rsp.data_len = rv - 1; + memcpy(rsp.data, resp + 1, rsp.data_len); + } + + /* return response */ + return &rsp; + } + + /* no valid response */ + return NULL; +} + +static int +ipmi_serial_term_setup(struct ipmi_intf * intf) +{ + intf->session = malloc(sizeof(struct ipmi_session)); + if (intf->session == NULL) { + lprintf(LOG_ERR, "ipmitool: malloc failure"); + return -1; + } + + memset(intf->session, 0, sizeof(struct ipmi_session)); + + /* setup default LAN maximum request and response sizes */ + intf->max_request_data_size = IPMI_SERIAL_MAX_RQ_SIZE; + intf->max_response_data_size = IPMI_SERIAL_MAX_RS_SIZE; + return 0; +} + +int +ipmi_serial_term_set_my_addr(struct ipmi_intf * intf, uint8_t addr) +{ + intf->my_addr = addr; + return 0; +} + +struct ipmi_intf ipmi_serial_term_intf = { + name: "serial-terminal", + desc: "Serial Interface, Terminal Mode", + setup: ipmi_serial_term_setup, + open: ipmi_serial_term_open, + close: ipmi_serial_term_close, + sendrecv: ipmi_serial_term_send_cmd, + set_my_addr:ipmi_serial_term_set_my_addr +}; |