diff packages/net/snmp/lib/current/src/lcd_time.c @ 103:95f3e12a6327 ecos-sw-2000-06-23

Merge from eCos master repository on 2000-06-23-16:41:10-BST
author jlarmour
date Fri, 23 Jun 2000 17:06:31 +0000
parents
children e0c0827131d1
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/net/snmp/lib/current/src/lcd_time.c
@@ -0,0 +1,638 @@
+//==========================================================================
+//
+//      ./lib/current/src/lcd_time.c
+//
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// Software distributed under the License is distributed on an "AS IS"      
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+// License for the specific language governing rights and limitations under 
+// the License.                                                             
+//                                                                          
+// The Original Code is eCos - Embedded Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//####UCDSNMPCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from the UCD-SNMP
+// project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
+// California at Davis, which was originally based on the Carnegie Mellon
+// University SNMP implementation.  Portions of this software are therefore
+// covered by the appropriate copyright disclaimers included herein.
+//
+// The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
+// -------------------------------------------
+//
+//####UCDSNMPCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    hmt
+// Contributors: hmt
+// Date:         2000-05-30
+// Purpose:      Port of UCD-SNMP distribution to eCos.
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+/********************************************************************
+       Copyright 1989, 1991, 1992 by Carnegie Mellon University
+
+			  Derivative Work -
+Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
+
+			 All Rights Reserved
+
+Permission to use, copy, modify and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appears in all copies and
+that both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of CMU and The Regents of
+the University of California not be used in advertising or publicity
+pertaining to distribution of the software without specific written
+permission.
+
+CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
+THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*********************************************************************/
+/*
+ * lcd_time.c
+ *
+ * XXX	Should etimelist entries with <0,0> time tuples be timed out?
+ * XXX	Need a routine to free the memory?  (Perhaps at shutdown?)
+ */
+
+#include <config.h>
+
+#include <sys/types.h>
+#if HAVE_WINSOCK_H
+#include <winsock.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#if TIME_WITH_SYS_TIME
+# ifdef WIN32
+#  include <sys/timeb.h>
+# else
+#  include <sys/time.h>
+# endif
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#if HAVE_DMALLOC_H
+#include <dmalloc.h>
+#endif
+
+#include "asn1.h"
+#include "snmp_api.h"
+#include "callback.h"
+#include "snmpusm.h"
+#include "lcd_time.h"
+#include "snmp_debug.h"
+#include "tools.h"
+#include "scapi.h"
+
+#include "transform_oids.h"
+
+
+/*
+ * Global static hashlist to contain Enginetime entries.
+ *
+ * New records are prepended to the appropriate list at the hash index.
+ */
+static Enginetime etimelist[ETIMELIST_SIZE];
+
+
+
+
+/*******************************************************************-o-******
+ * get_enginetime
+ *
+ * Parameters:
+ *	*engineID
+ *	 engineID_len
+ *	*engineboot
+ *	*engine_time
+ *      
+ * Returns:
+ *	SNMPERR_SUCCESS		Success -- when a record for engineID is found.
+ *	SNMPERR_GENERR		Otherwise.
+ *
+ *
+ * Lookup engineID and return the recorded values for the
+ * <engine_time, engineboot> tuple adjusted to reflect the estimated time
+ * at the engine in question.
+ *
+ * Special case: if engineID is NULL or if engineID_len is 0 then
+ * the time tuple is returned immediately as zero.
+ *
+ * XXX	What if timediff wraps?  >shrug<
+ * XXX  Then: you need to increment the boots value.  Now.  Detecting
+ *            this is another matter.
+ */
+int
+get_enginetime(	u_char	*engineID,	
+		u_int	 engineID_len,
+		u_int	*engineboot,
+		u_int	*engine_time,
+		u_int   authenticated)
+{
+	int		rval	 = SNMPERR_SUCCESS;
+	time_t		timediff = 0;
+	Enginetime	e	 = NULL;
+
+
+
+	/*
+	 * Sanity check.
+	 */
+	if ( !engine_time || !engineboot ) {
+		QUITFUN(SNMPERR_GENERR, get_enginetime_quit);
+	}
+
+
+	/*
+	 * Compute estimated current engine_time tuple at engineID if
+	 * a record is cached for it.
+	 */
+	*engine_time = *engineboot = 0;
+
+	if ( !engineID || (engineID_len<=0) ) {
+		QUITFUN(SNMPERR_GENERR, get_enginetime_quit);
+	}
+
+	if ( !(e = search_enginetime_list(engineID, engineID_len)) ) {
+		QUITFUN(SNMPERR_GENERR, get_enginetime_quit);
+	}
+
+#ifdef LCD_TIME_SYNC_OPT
+        if (!authenticated || e->authenticatedFlag) {
+#endif	
+	*engine_time = e->engineTime;
+	*engineboot = e->engineBoot;
+
+	timediff = time(NULL) - e->lastReceivedEngineTime;
+#ifdef LCD_TIME_SYNC_OPT	
+        }
+#endif	
+
+	if ( timediff > (int)(ENGINETIME_MAX - *engine_time) ) {
+		*engine_time = (timediff - (ENGINETIME_MAX - *engine_time));
+
+		/* FIX -- move this check up... should not change anything
+		 * if engineboot is already locked.  ???
+		 */
+		if (*engineboot < ENGINEBOOT_MAX) {
+			*engineboot += 1;
+		}
+
+	} else {
+		*engine_time += timediff;
+	}
+
+        DEBUGMSGTL(("lcd_get_enginetime", "engineID "));
+        DEBUGMSGHEX(("lcd_get_enginetime", engineID, engineID_len));
+        DEBUGMSG(("lcd_get_enginetime", ": boots=%d, time=%d\n", *engineboot,
+                  *engine_time));
+
+get_enginetime_quit:
+	return rval;
+
+}  /* end get_enginetime() */
+
+/*******************************************************************-o-******
+ * get_enginetime
+ *
+ * Parameters:
+ *	*engineID
+ *	 engineID_len
+ *	*engineboot
+ *	*engine_time
+ *      
+ * Returns:
+ *	SNMPERR_SUCCESS		Success -- when a record for engineID is found.
+ *	SNMPERR_GENERR		Otherwise.
+ *
+ *
+ * Lookup engineID and return the recorded values for the
+ * <engine_time, engineboot> tuple adjusted to reflect the estimated time
+ * at the engine in question.
+ *
+ * Special case: if engineID is NULL or if engineID_len is 0 then
+ * the time tuple is returned immediately as zero.
+ *
+ * XXX	What if timediff wraps?  >shrug<
+ * XXX  Then: you need to increment the boots value.  Now.  Detecting
+ *            this is another matter.
+ */
+int
+get_enginetime_ex(	u_char	*engineID,	
+		u_int	 engineID_len,
+		u_int	*engineboot,
+		u_int	*engine_time,
+		u_int	*last_engine_time,
+		u_int   authenticated)
+{
+	int		rval	 = SNMPERR_SUCCESS;
+	time_t		timediff = 0;
+	Enginetime	e	 = NULL;
+
+
+
+	/*
+	 * Sanity check.
+	 */
+	if ( !engine_time || !engineboot || !last_engine_time) {
+		QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit);
+	}
+
+
+	/*
+	 * Compute estimated current engine_time tuple at engineID if
+	 * a record is cached for it.
+	 */
+	*last_engine_time = *engine_time = *engineboot = 0;
+
+	if ( !engineID || (engineID_len<=0) ) {
+		QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit);
+	}
+
+	if ( !(e = search_enginetime_list(engineID, engineID_len)) ) {
+		QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit);
+	}
+
+#ifdef LCD_TIME_SYNC_OPT
+        if (!authenticated || e->authenticatedFlag) {
+#endif	
+	*last_engine_time = *engine_time = e->engineTime;
+	*engineboot = e->engineBoot;
+
+	timediff = time(NULL) - e->lastReceivedEngineTime;
+#ifdef LCD_TIME_SYNC_OPT	
+        }
+#endif	
+
+	if ( timediff > (int)(ENGINETIME_MAX - *engine_time) ) {
+		*engine_time = (timediff - (ENGINETIME_MAX - *engine_time));
+
+		/* FIX -- move this check up... should not change anything
+		 * if engineboot is already locked.  ???
+		 */
+		if (*engineboot < ENGINEBOOT_MAX) {
+			*engineboot += 1;
+		}
+
+	} else {
+		*engine_time += timediff;
+	}
+
+        DEBUGMSGTL(("lcd_get_enginetime_ex", "engineID "));
+        DEBUGMSGHEX(("lcd_get_enginetime_ex", engineID, engineID_len));
+        DEBUGMSG(("lcd_get_enginetime_ex", ": boots=%d, time=%d\n", *engineboot,
+                  *engine_time));
+
+get_enginetime_ex_quit:
+	return rval;
+
+}  /* end get_enginetime_ex() */
+
+
+
+
+/*******************************************************************-o-******
+ * set_enginetime
+ *
+ * Parameters:
+ *	*engineID
+ *	 engineID_len
+ *	 engineboot
+ *	 engine_time
+ *      
+ * Returns:
+ *	SNMPERR_SUCCESS		Success.
+ *	SNMPERR_GENERR		Otherwise.
+ *
+ *
+ * Lookup engineID and store the given <engine_time, engineboot> tuple
+ * and then stamp the record with a consistent source of local time.
+ * If the engineID record does not exist, create one.
+ *
+ * Special case: engineID is NULL or engineID_len is 0 defines an engineID
+ * that is "always set."
+ *
+ * XXX	"Current time within the local engine" == time(NULL)...
+ */
+int
+set_enginetime(	u_char	*engineID,
+		u_int	 engineID_len,
+		u_int	 engineboot,
+		u_int  	 engine_time,
+		u_int    authenticated)
+{
+	int		rval = SNMPERR_SUCCESS,
+			iindex;
+	Enginetime	e = NULL;
+
+
+
+	/*
+	 * Sanity check.
+	 */
+	if ( !engineID || (engineID_len <= 0) ) {
+		return rval;
+	}
+
+
+	/*
+	 * Store the given <engine_time, engineboot> tuple in the record
+	 * for engineID.  Create a new record if necessary.
+	 */
+	if ( !(e = search_enginetime_list(engineID, engineID_len)) )
+	{
+		if ( (iindex = hash_engineID(engineID, engineID_len)) < 0 )
+		{
+			QUITFUN(SNMPERR_GENERR, set_enginetime_quit);
+		}
+
+		e = (Enginetime) calloc(1,sizeof(*e));
+
+		e->next = etimelist[iindex];
+		etimelist[iindex] = e;
+
+		e->engineID = (u_char *) calloc(1,engineID_len);
+		memcpy(e->engineID, engineID, engineID_len);
+
+		e->engineID_len = engineID_len;
+	}
+#ifdef LCD_TIME_SYNC_OPT	
+	if (authenticated || !e->authenticatedFlag) {
+	  e->authenticatedFlag = authenticated;
+#else
+	if (authenticated) {
+#endif
+	  e->engineTime		  = engine_time;
+	  e->engineBoot		  = engineboot;
+	  e->lastReceivedEngineTime = time(NULL);
+        }
+
+	e = NULL;	/* Indicates a successful update. */
+
+        DEBUGMSGTL(("lcd_set_enginetime", "engineID "));
+        DEBUGMSGHEX(("lcd_set_enginetime", engineID, engineID_len));
+        DEBUGMSG(("lcd_set_enginetime", ": boots=%d, time=%d\n", engineboot,
+                  engine_time));
+
+set_enginetime_quit:
+	SNMP_FREE(e);
+
+	return rval;
+
+}  /* end set_enginetime() */
+
+
+
+
+/*******************************************************************-o-******
+ * search_enginetime_list
+ *
+ * Parameters:
+ *	*engineID
+ *	 engineID_len
+ *      
+ * Returns:
+ *	Pointer to a etimelist record with engineID <engineID>  -OR-
+ *	NULL if no record exists.
+ *
+ *
+ * Search etimelist for an entry with engineID.
+ *
+ * ASSUMES that no engineID will have more than one record in the list.
+ */
+Enginetime
+search_enginetime_list(u_char *engineID, u_int engineID_len)
+{
+	int		rval = SNMPERR_SUCCESS;
+	Enginetime	e    = NULL;
+
+
+	/*
+	 * Sanity check.
+	 */
+	if ( !engineID || (engineID_len<=0) ) {
+		QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit);
+	}
+
+
+	/*
+	 * Find the entry for engineID if there be one.
+	 */
+	rval = hash_engineID(engineID, engineID_len);
+	if (rval < 0) {
+		QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit);
+	}
+	e = etimelist[rval];
+
+	for ( /*EMPTY*/; e; e = e->next )
+	{
+		if ( (engineID_len == e->engineID_len)
+			&& !memcmp(e->engineID, engineID, engineID_len) )
+		{
+			break;
+		}
+	}
+	
+
+search_enginetime_list_quit:
+	return e;
+
+}  /* end search_enginetime_list() */
+
+
+
+
+
+/*******************************************************************-o-******
+ * hash_engineID
+ *
+ * Parameters:
+ *	*engineID
+ *	 engineID_len
+ *      
+ * Returns:
+ *	>0			etimelist index for this engineID.
+ *	SNMPERR_GENERR		Error.
+ *	
+ * 
+ * Use a cheap hash to build an index into the etimelist.  Method is 
+ * to hash the engineID, then split the hash into u_int's and add them up
+ * and modulo the size of the list.
+ *
+ */
+int
+hash_engineID(u_char *engineID, u_int engineID_len)
+{
+	int		 rval		= SNMPERR_GENERR;
+	size_t		 buf_len	= SNMP_MAXBUF;
+	u_int		 additive	= 0;
+	u_char		*bufp,
+			 buf[SNMP_MAXBUF];
+	void		*context = NULL;
+
+
+
+	/*
+	 * Sanity check.
+	 */
+	if ( !engineID || (engineID_len <= 0) ) {
+		QUITFUN(SNMPERR_GENERR, hash_engineID_quit);
+	}
+
+
+	/*
+	 * Hash engineID into a list index.
+	 */
+        rval = sc_hash(usmHMACMD5AuthProtocol,
+                       sizeof(usmHMACMD5AuthProtocol)/sizeof(oid),
+                       engineID, engineID_len,
+                       buf, &buf_len);
+	QUITFUN(rval, hash_engineID_quit);
+        
+	for ( bufp = buf; (bufp-buf) < (int)buf_len; bufp += 4 ) {
+		additive += (u_int) *bufp;
+	}
+
+hash_engineID_quit:
+	SNMP_FREE(context);
+	memset(buf, 0, SNMP_MAXBUF);
+
+	return (rval < 0) ? rval : (additive % ETIMELIST_SIZE);
+
+}  /* end hash_engineID() */
+
+
+
+
+#ifdef SNMP_TESTING_CODE
+/*******************************************************************-o-******
+ * dump_etimelist_entry
+ *
+ * Parameters:
+ *	e
+ *	count
+ */
+void
+dump_etimelist_entry(Enginetime e, int count)
+{
+	u_int	 buflen;
+	char	 tabs[SNMP_MAXBUF],
+		*t = tabs, 
+		*s;
+
+
+
+	count += 1;
+	while (count--) {
+		t += sprintf(t, "  ");
+	}
+
+
+	buflen = e->engineID_len;
+#ifdef SNMP_TESTING_CODE
+	if ( !(s = dump_snmpEngineID(e->engineID, &buflen)) ) {
+#endif
+		binary_to_hex(e->engineID, e->engineID_len, &s);
+#ifdef SNMP_TESTING_CODE
+	}
+#endif
+
+	DEBUGMSGTL(("dump_etimelist", "%s\n",tabs));
+	DEBUGMSGTL(("dump_etimelist", "%s%s (len=%d) <%d,%d>\n", tabs,
+                    s, e->engineID_len,
+                    e->engineTime, e->engineBoot));
+	DEBUGMSGTL(("dump_etimelist", "%s%ld (%ld) -- %s", tabs,
+                    e->lastReceivedEngineTime,
+                    time(NULL) - e->lastReceivedEngineTime,
+                    ctime(&e->lastReceivedEngineTime)));
+
+	SNMP_FREE(s);
+
+}  /* end dump_etimelist_entry() */
+
+
+
+
+/*******************************************************************-o-******
+ * dump_etimelist
+ */
+void
+dump_etimelist(void)
+{
+	int		iindex = -1,
+			count = 0;
+	Enginetime	e;
+
+
+
+	DEBUGMSGTL(("dump_etimelist", "\n"));
+
+	while (++iindex < ETIMELIST_SIZE) {
+		DEBUGMSG(("dump_etimelist", "[%d]", iindex));
+
+		count = 0;
+		e = etimelist[iindex];
+
+		while (e) {
+			dump_etimelist_entry(e, count++);
+			e = e->next;
+		}
+
+		if (count > 0) {
+			DEBUGMSG(("dump_etimelist", "\n"));
+		}
+	}  /* endwhile */
+
+	DEBUGMSG(("dump_etimelist", "\n"));
+
+}  /* end dump_etimelist() */
+#endif /* SNMP_TESTING_CODE */