diff options
Diffstat (limited to 'src/plugins/lan')
-rw-r--r-- | src/plugins/lan/Makefile.am | 39 | ||||
-rw-r--r-- | src/plugins/lan/Makefile.in | 540 | ||||
-rw-r--r-- | src/plugins/lan/asf.h | 75 | ||||
-rw-r--r-- | src/plugins/lan/auth.c | 220 | ||||
-rw-r--r-- | src/plugins/lan/auth.h | 40 | ||||
-rw-r--r-- | src/plugins/lan/lan.c | 2112 | ||||
-rw-r--r-- | src/plugins/lan/lan.h | 41 | ||||
-rw-r--r-- | src/plugins/lan/md5.c | 381 | ||||
-rw-r--r-- | src/plugins/lan/md5.h | 91 | ||||
-rw-r--r-- | src/plugins/lan/rmcp.h | 99 |
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 */ |