00001 /* 00002 * lcd_time.c 00003 * 00004 * XXX Should etimelist entries with <0,0> time tuples be timed out? 00005 * XXX Need a routine to free the memory? (Perhaps at shutdown?) 00006 */ 00007 00008 #include <net-snmp/net-snmp-config.h> 00009 00010 #include <sys/types.h> 00011 #if HAVE_WINSOCK_H 00012 #include <winsock.h> 00013 #endif 00014 #include <stdio.h> 00015 #ifdef HAVE_STDLIB_H 00016 #include <stdlib.h> 00017 #endif 00018 #if HAVE_STRING_H 00019 #include <string.h> 00020 #else 00021 #include <strings.h> 00022 #endif 00023 #if TIME_WITH_SYS_TIME 00024 # ifdef WIN32 00025 # include <sys/timeb.h> 00026 # else 00027 # include <sys/time.h> 00028 # endif 00029 # include <time.h> 00030 #else 00031 # if HAVE_SYS_TIME_H 00032 # include <sys/time.h> 00033 # else 00034 # include <time.h> 00035 # endif 00036 #endif 00037 #ifdef HAVE_NETINET_IN_H 00038 #include <netinet/in.h> 00039 #endif 00040 00041 #if HAVE_DMALLOC_H 00042 #include <dmalloc.h> 00043 #endif 00044 00045 #include <net-snmp/types.h> 00046 #include <net-snmp/output_api.h> 00047 #include <net-snmp/utilities.h> 00048 00049 #include <net-snmp/library/snmp_api.h> 00050 #include <net-snmp/library/callback.h> 00051 #include <net-snmp/library/snmp_secmod.h> 00052 #include <net-snmp/library/snmpusm.h> 00053 #include <net-snmp/library/lcd_time.h> 00054 #include <net-snmp/library/scapi.h> 00055 #include <net-snmp/library/snmpv3.h> 00056 00057 #include <net-snmp/library/transform_oids.h> 00058 00059 /* 00060 * Global static hashlist to contain Enginetime entries. 00061 * 00062 * New records are prepended to the appropriate list at the hash index. 00063 */ 00064 static Enginetime etimelist[ETIMELIST_SIZE]; 00065 00066 00067 00068 00069 /*******************************************************************-o-****** 00070 * get_enginetime 00071 * 00072 * Parameters: 00073 * *engineID 00074 * engineID_len 00075 * *engineboot 00076 * *engine_time 00077 * 00078 * Returns: 00079 * SNMPERR_SUCCESS Success -- when a record for engineID is found. 00080 * SNMPERR_GENERR Otherwise. 00081 * 00082 * 00083 * Lookup engineID and return the recorded values for the 00084 * <engine_time, engineboot> tuple adjusted to reflect the estimated time 00085 * at the engine in question. 00086 * 00087 * Special case: if engineID is NULL or if engineID_len is 0 then 00088 * the time tuple is returned immediately as zero. 00089 * 00090 * XXX What if timediff wraps? >shrug< 00091 * XXX Then: you need to increment the boots value. Now. Detecting 00092 * this is another matter. 00093 */ 00094 int 00095 get_enginetime(u_char * engineID, 00096 u_int engineID_len, 00097 u_int * engineboot, 00098 u_int * engine_time, u_int authenticated) 00099 { 00100 int rval = SNMPERR_SUCCESS; 00101 time_t timediff = 0; 00102 Enginetime e = NULL; 00103 00104 00105 00106 /* 00107 * Sanity check. 00108 */ 00109 if (!engine_time || !engineboot) { 00110 QUITFUN(SNMPERR_GENERR, get_enginetime_quit); 00111 } 00112 00113 00114 /* 00115 * Compute estimated current engine_time tuple at engineID if 00116 * a record is cached for it. 00117 */ 00118 *engine_time = *engineboot = 0; 00119 00120 if (!engineID || (engineID_len <= 0)) { 00121 QUITFUN(SNMPERR_GENERR, get_enginetime_quit); 00122 } 00123 00124 if (!(e = search_enginetime_list(engineID, engineID_len))) { 00125 QUITFUN(SNMPERR_GENERR, get_enginetime_quit); 00126 } 00127 #ifdef LCD_TIME_SYNC_OPT 00128 if (!authenticated || e->authenticatedFlag) { 00129 #endif 00130 *engine_time = e->engineTime; 00131 *engineboot = e->engineBoot; 00132 00133 timediff = snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime; 00134 00135 #ifdef LCD_TIME_SYNC_OPT 00136 } 00137 #endif 00138 00139 if (timediff > (int) (ENGINETIME_MAX - *engine_time)) { 00140 *engine_time = (timediff - (ENGINETIME_MAX - *engine_time)); 00141 00142 /* 00143 * FIX -- move this check up... should not change anything 00144 * * if engineboot is already locked. ??? 00145 */ 00146 if (*engineboot < ENGINEBOOT_MAX) { 00147 *engineboot += 1; 00148 } 00149 00150 } else { 00151 *engine_time += timediff; 00152 } 00153 00154 DEBUGMSGTL(("lcd_get_enginetime", "engineID ")); 00155 DEBUGMSGHEX(("lcd_get_enginetime", engineID, engineID_len)); 00156 DEBUGMSG(("lcd_get_enginetime", ": boots=%d, time=%d\n", *engineboot, 00157 *engine_time)); 00158 00159 get_enginetime_quit: 00160 return rval; 00161 00162 } /* end get_enginetime() */ 00163 00164 /*******************************************************************-o-****** 00165 * get_enginetime 00166 * 00167 * Parameters: 00168 * *engineID 00169 * engineID_len 00170 * *engineboot 00171 * *engine_time 00172 * 00173 * Returns: 00174 * SNMPERR_SUCCESS Success -- when a record for engineID is found. 00175 * SNMPERR_GENERR Otherwise. 00176 * 00177 * 00178 * Lookup engineID and return the recorded values for the 00179 * <engine_time, engineboot> tuple adjusted to reflect the estimated time 00180 * at the engine in question. 00181 * 00182 * Special case: if engineID is NULL or if engineID_len is 0 then 00183 * the time tuple is returned immediately as zero. 00184 * 00185 * XXX What if timediff wraps? >shrug< 00186 * XXX Then: you need to increment the boots value. Now. Detecting 00187 * this is another matter. 00188 */ 00189 int 00190 get_enginetime_ex(u_char * engineID, 00191 u_int engineID_len, 00192 u_int * engineboot, 00193 u_int * engine_time, 00194 u_int * last_engine_time, u_int authenticated) 00195 { 00196 int rval = SNMPERR_SUCCESS; 00197 time_t timediff = 0; 00198 Enginetime e = NULL; 00199 00200 00201 00202 /* 00203 * Sanity check. 00204 */ 00205 if (!engine_time || !engineboot || !last_engine_time) { 00206 QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit); 00207 } 00208 00209 00210 /* 00211 * Compute estimated current engine_time tuple at engineID if 00212 * a record is cached for it. 00213 */ 00214 *last_engine_time = *engine_time = *engineboot = 0; 00215 00216 if (!engineID || (engineID_len <= 0)) { 00217 QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit); 00218 } 00219 00220 if (!(e = search_enginetime_list(engineID, engineID_len))) { 00221 QUITFUN(SNMPERR_GENERR, get_enginetime_ex_quit); 00222 } 00223 #ifdef LCD_TIME_SYNC_OPT 00224 if (!authenticated || e->authenticatedFlag) { 00225 #endif 00226 *last_engine_time = *engine_time = e->engineTime; 00227 *engineboot = e->engineBoot; 00228 00229 timediff = snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime; 00230 00231 #ifdef LCD_TIME_SYNC_OPT 00232 } 00233 #endif 00234 00235 if (timediff > (int) (ENGINETIME_MAX - *engine_time)) { 00236 *engine_time = (timediff - (ENGINETIME_MAX - *engine_time)); 00237 00238 /* 00239 * FIX -- move this check up... should not change anything 00240 * * if engineboot is already locked. ??? 00241 */ 00242 if (*engineboot < ENGINEBOOT_MAX) { 00243 *engineboot += 1; 00244 } 00245 00246 } else { 00247 *engine_time += timediff; 00248 } 00249 00250 DEBUGMSGTL(("lcd_get_enginetime_ex", "engineID ")); 00251 DEBUGMSGHEX(("lcd_get_enginetime_ex", engineID, engineID_len)); 00252 DEBUGMSG(("lcd_get_enginetime_ex", ": boots=%d, time=%d\n", 00253 *engineboot, *engine_time)); 00254 00255 get_enginetime_ex_quit: 00256 return rval; 00257 00258 } /* end get_enginetime_ex() */ 00259 00260 00261 void free_enginetime(unsigned char *engineID, size_t engineID_len) 00262 { 00263 Enginetime e = NULL; 00264 int rval = 0; 00265 00266 rval = hash_engineID(engineID, engineID_len); 00267 if (rval < 0) 00268 return; 00269 00270 e = etimelist[rval]; 00271 00272 while (e != NULL) { 00273 etimelist[rval] = e->next; 00274 SNMP_FREE(e->engineID); 00275 SNMP_FREE(e); 00276 e = etimelist[rval]; 00277 } 00278 00279 } 00280 00281 00282 00283 /*******************************************************************-o-****** 00284 * set_enginetime 00285 * 00286 * Parameters: 00287 * *engineID 00288 * engineID_len 00289 * engineboot 00290 * engine_time 00291 * 00292 * Returns: 00293 * SNMPERR_SUCCESS Success. 00294 * SNMPERR_GENERR Otherwise. 00295 * 00296 * 00297 * Lookup engineID and store the given <engine_time, engineboot> tuple 00298 * and then stamp the record with a consistent source of local time. 00299 * If the engineID record does not exist, create one. 00300 * 00301 * Special case: engineID is NULL or engineID_len is 0 defines an engineID 00302 * that is "always set." 00303 * 00304 * XXX "Current time within the local engine" == time(NULL)... 00305 */ 00306 int 00307 set_enginetime(u_char * engineID, 00308 u_int engineID_len, 00309 u_int engineboot, u_int engine_time, u_int authenticated) 00310 { 00311 int rval = SNMPERR_SUCCESS, iindex; 00312 Enginetime e = NULL; 00313 00314 00315 00316 /* 00317 * Sanity check. 00318 */ 00319 if (!engineID || (engineID_len <= 0)) { 00320 return rval; 00321 } 00322 00323 00324 /* 00325 * Store the given <engine_time, engineboot> tuple in the record 00326 * for engineID. Create a new record if necessary. 00327 */ 00328 if (!(e = search_enginetime_list(engineID, engineID_len))) { 00329 if ((iindex = hash_engineID(engineID, engineID_len)) < 0) { 00330 QUITFUN(SNMPERR_GENERR, set_enginetime_quit); 00331 } 00332 00333 e = (Enginetime) calloc(1, sizeof(*e)); 00334 00335 e->next = etimelist[iindex]; 00336 etimelist[iindex] = e; 00337 00338 e->engineID = (u_char *) calloc(1, engineID_len); 00339 memcpy(e->engineID, engineID, engineID_len); 00340 00341 e->engineID_len = engineID_len; 00342 } 00343 #ifdef LCD_TIME_SYNC_OPT 00344 if (authenticated || !e->authenticatedFlag) { 00345 e->authenticatedFlag = authenticated; 00346 #else 00347 if (authenticated) { 00348 #endif 00349 e->engineTime = engine_time; 00350 e->engineBoot = engineboot; 00351 e->lastReceivedEngineTime = snmpv3_local_snmpEngineTime(); 00352 } 00353 00354 e = NULL; /* Indicates a successful update. */ 00355 00356 DEBUGMSGTL(("lcd_set_enginetime", "engineID ")); 00357 DEBUGMSGHEX(("lcd_set_enginetime", engineID, engineID_len)); 00358 DEBUGMSG(("lcd_set_enginetime", ": boots=%d, time=%d\n", engineboot, 00359 engine_time)); 00360 00361 set_enginetime_quit: 00362 SNMP_FREE(e); 00363 00364 return rval; 00365 00366 } /* end set_enginetime() */ 00367 00368 00369 00370 00371 /*******************************************************************-o-****** 00372 * search_enginetime_list 00373 * 00374 * Parameters: 00375 * *engineID 00376 * engineID_len 00377 * 00378 * Returns: 00379 * Pointer to a etimelist record with engineID <engineID> -OR- 00380 * NULL if no record exists. 00381 * 00382 * 00383 * Search etimelist for an entry with engineID. 00384 * 00385 * ASSUMES that no engineID will have more than one record in the list. 00386 */ 00387 Enginetime 00388 search_enginetime_list(u_char * engineID, u_int engineID_len) 00389 { 00390 int rval = SNMPERR_SUCCESS; 00391 Enginetime e = NULL; 00392 00393 00394 /* 00395 * Sanity check. 00396 */ 00397 if (!engineID || (engineID_len <= 0)) { 00398 QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit); 00399 } 00400 00401 00402 /* 00403 * Find the entry for engineID if there be one. 00404 */ 00405 rval = hash_engineID(engineID, engineID_len); 00406 if (rval < 0) { 00407 QUITFUN(SNMPERR_GENERR, search_enginetime_list_quit); 00408 } 00409 e = etimelist[rval]; 00410 00411 for ( /*EMPTY*/; e; e = e->next) { 00412 if ((engineID_len == e->engineID_len) 00413 && !memcmp(e->engineID, engineID, engineID_len)) { 00414 break; 00415 } 00416 } 00417 00418 00419 search_enginetime_list_quit: 00420 return e; 00421 00422 } /* end search_enginetime_list() */ 00423 00424 00425 00426 00427 00428 /*******************************************************************-o-****** 00429 * hash_engineID 00430 * 00431 * Parameters: 00432 * *engineID 00433 * engineID_len 00434 * 00435 * Returns: 00436 * >0 etimelist index for this engineID. 00437 * SNMPERR_GENERR Error. 00438 * 00439 * 00440 * Use a cheap hash to build an index into the etimelist. Method is 00441 * to hash the engineID, then split the hash into u_int's and add them up 00442 * and modulo the size of the list. 00443 * 00444 */ 00445 int 00446 hash_engineID(u_char * engineID, u_int engineID_len) 00447 { 00448 int rval = SNMPERR_GENERR; 00449 size_t buf_len = SNMP_MAXBUF; 00450 u_int additive = 0; 00451 u_char *bufp, buf[SNMP_MAXBUF]; 00452 void *context = NULL; 00453 00454 00455 00456 /* 00457 * Sanity check. 00458 */ 00459 if (!engineID || (engineID_len <= 0)) { 00460 QUITFUN(SNMPERR_GENERR, hash_engineID_quit); 00461 } 00462 00463 00464 /* 00465 * Hash engineID into a list index. 00466 */ 00467 #ifndef DISABLE_MD5 00468 rval = sc_hash(usmHMACMD5AuthProtocol, 00469 sizeof(usmHMACMD5AuthProtocol) / sizeof(oid), 00470 engineID, engineID_len, buf, &buf_len); 00471 #else 00472 rval = sc_hash(usmHMACSHA1AuthProtocol, 00473 sizeof(usmHMACSHA1AuthProtocol) / sizeof(oid), 00474 engineID, engineID_len, buf, &buf_len); 00475 #endif 00476 QUITFUN(rval, hash_engineID_quit); 00477 00478 for (bufp = buf; (bufp - buf) < (int) buf_len; bufp += 4) { 00479 additive += (u_int) * bufp; 00480 } 00481 00482 hash_engineID_quit: 00483 SNMP_FREE(context); 00484 memset(buf, 0, SNMP_MAXBUF); 00485 00486 return (rval < 0) ? rval : (additive % ETIMELIST_SIZE); 00487 00488 } /* end hash_engineID() */ 00489 00490 00491 00492 00493 #ifdef SNMP_TESTING_CODE 00494 /*******************************************************************-o-****** 00495 * dump_etimelist_entry 00496 * 00497 * Parameters: 00498 * e 00499 * count 00500 */ 00501 void 00502 dump_etimelist_entry(Enginetime e, int count) 00503 { 00504 u_int buflen; 00505 char tabs[SNMP_MAXBUF], *t = tabs, *s; 00506 00507 00508 00509 count += 1; 00510 while (count--) { 00511 t += sprintf(t, " "); 00512 } 00513 00514 00515 buflen = e->engineID_len; 00516 #ifdef SNMP_TESTING_CODE 00517 if (!(s = dump_snmpEngineID(e->engineID, &buflen))) { 00518 #endif 00519 binary_to_hex(e->engineID, e->engineID_len, &s); 00520 #ifdef SNMP_TESTING_CODE 00521 } 00522 #endif 00523 00524 DEBUGMSGTL(("dump_etimelist", "%s\n", tabs)); 00525 DEBUGMSGTL(("dump_etimelist", "%s%s (len=%d) <%d,%d>\n", tabs, 00526 s, e->engineID_len, e->engineTime, e->engineBoot)); 00527 DEBUGMSGTL(("dump_etimelist", "%s%ld (%ld)", tabs, 00528 e->lastReceivedEngineTime, 00529 snmpv3_local_snmpEngineTime() - e->lastReceivedEngineTime)); 00530 00531 SNMP_FREE(s); 00532 00533 } /* end dump_etimelist_entry() */ 00534 00535 00536 00537 00538 /*******************************************************************-o-****** 00539 * dump_etimelist 00540 */ 00541 void 00542 dump_etimelist(void) 00543 { 00544 int iindex = -1, count = 0; 00545 Enginetime e; 00546 00547 00548 00549 DEBUGMSGTL(("dump_etimelist", "\n")); 00550 00551 while (++iindex < ETIMELIST_SIZE) { 00552 DEBUGMSG(("dump_etimelist", "[%d]", iindex)); 00553 00554 count = 0; 00555 e = etimelist[iindex]; 00556 00557 while (e) { 00558 dump_etimelist_entry(e, count++); 00559 e = e->next; 00560 } 00561 00562 if (count > 0) { 00563 DEBUGMSG(("dump_etimelist", "\n")); 00564 } 00565 } /* endwhile */ 00566 00567 DEBUGMSG(("dump_etimelist", "\n")); 00568 00569 } /* end dump_etimelist() */ 00570 #endif /* SNMP_TESTING_CODE */
1.3.9.1
Last modified: Thursday, 01-Mar-2007 16:20:01 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.