summaryrefslogtreecommitdiff
path: root/src/plugins/lan
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-23 15:03:00 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-23 15:03:00 +0200
commitb32d92e890caac903491116e9d817aa780c0323b (patch)
tree5a135c37eaa9ac94772819a28ce5beedd18e5c4a /src/plugins/lan
parentc3445516ecd58e97de483cf4b7fafcc1104890d7 (diff)
Imported Upstream version 1.8.14upstream/1.8.14
Diffstat (limited to 'src/plugins/lan')
-rw-r--r--src/plugins/lan/Makefile.am39
-rw-r--r--src/plugins/lan/Makefile.in540
-rw-r--r--src/plugins/lan/asf.h75
-rw-r--r--src/plugins/lan/auth.c220
-rw-r--r--src/plugins/lan/auth.h40
-rw-r--r--src/plugins/lan/lan.c2112
-rw-r--r--src/plugins/lan/lan.h41
-rw-r--r--src/plugins/lan/md5.c381
-rw-r--r--src/plugins/lan/md5.h91
-rw-r--r--src/plugins/lan/rmcp.h99
10 files changed, 3638 insertions, 0 deletions
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 */