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 +};  | 
