net-snmp 5.7
|
00001 /* 00002 * baby_steps.c 00003 * $Id$ 00004 */ 00005 #include <net-snmp/net-snmp-config.h> 00006 #include <net-snmp/net-snmp-features.h> 00007 #include <net-snmp/net-snmp-includes.h> 00008 #include <net-snmp/agent/net-snmp-agent-includes.h> 00009 00010 netsnmp_feature_provide(baby_steps) 00011 netsnmp_feature_child_of(baby_steps, mib_helpers) 00012 00013 #ifdef NETSNMP_FEATURE_REQUIRE_BABY_STEPS 00014 netsnmp_feature_require(check_requests_error) 00015 #endif 00016 00017 #ifndef NETSNMP_FEATURE_REMOVE_BABY_STEPS 00018 00019 #include <net-snmp/agent/baby_steps.h> 00020 00021 #define BABY_STEPS_PER_MODE_MAX 4 00022 #define BSTEP_USE_ORIGINAL 0xffff 00023 00024 static u_short get_mode_map[BABY_STEPS_PER_MODE_MAX] = { 00025 MODE_BSTEP_PRE_REQUEST, MODE_BSTEP_OBJECT_LOOKUP, BSTEP_USE_ORIGINAL, MODE_BSTEP_POST_REQUEST }; 00026 00027 #ifndef NETSNMP_NO_WRITE_SUPPORT 00028 static u_short set_mode_map[SNMP_MSG_INTERNAL_SET_MAX][BABY_STEPS_PER_MODE_MAX] = { 00029 /*R1*/ 00030 { MODE_BSTEP_PRE_REQUEST, MODE_BSTEP_OBJECT_LOOKUP, MODE_BSTEP_ROW_CREATE, 00031 MODE_BSTEP_CHECK_VALUE }, 00032 /*R2*/ 00033 { MODE_BSTEP_UNDO_SETUP, BABY_STEP_NONE, BABY_STEP_NONE, BABY_STEP_NONE }, 00034 /*A */ 00035 { MODE_BSTEP_SET_VALUE,MODE_BSTEP_CHECK_CONSISTENCY, 00036 MODE_BSTEP_COMMIT, BABY_STEP_NONE }, 00037 /*C */ 00038 { MODE_BSTEP_IRREVERSIBLE_COMMIT, MODE_BSTEP_UNDO_CLEANUP, MODE_BSTEP_POST_REQUEST, 00039 BABY_STEP_NONE}, 00040 /*F */ 00041 { MODE_BSTEP_UNDO_CLEANUP, MODE_BSTEP_POST_REQUEST, BABY_STEP_NONE, 00042 BABY_STEP_NONE }, 00043 /*U */ 00044 { MODE_BSTEP_UNDO_COMMIT, MODE_BSTEP_UNDO_SET, MODE_BSTEP_UNDO_CLEANUP, 00045 MODE_BSTEP_POST_REQUEST} 00046 }; 00047 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 00048 00049 static int 00050 _baby_steps_helper(netsnmp_mib_handler *handler, 00051 netsnmp_handler_registration *reginfo, 00052 netsnmp_agent_request_info *reqinfo, 00053 netsnmp_request_info *requests); 00054 static int 00055 _baby_steps_access_multiplexer(netsnmp_mib_handler *handler, 00056 netsnmp_handler_registration *reginfo, 00057 netsnmp_agent_request_info *reqinfo, 00058 netsnmp_request_info *requests); 00059 00066 static netsnmp_baby_steps_modes * 00067 netsnmp_baby_steps_modes_ref(netsnmp_baby_steps_modes *md) 00068 { 00069 md->refcnt++; 00070 return md; 00071 } 00072 00073 static void 00074 netsnmp_baby_steps_modes_deref(netsnmp_baby_steps_modes *md) 00075 { 00076 if (--md->refcnt == 0) 00077 free(md); 00078 } 00079 00083 netsnmp_mib_handler * 00084 netsnmp_baby_steps_handler_get(u_long modes) 00085 { 00086 netsnmp_mib_handler *mh; 00087 netsnmp_baby_steps_modes *md; 00088 00089 mh = netsnmp_create_handler("baby_steps", _baby_steps_helper); 00090 if(!mh) 00091 return NULL; 00092 00093 md = SNMP_MALLOC_TYPEDEF(netsnmp_baby_steps_modes); 00094 if (NULL == md) { 00095 snmp_log(LOG_ERR,"malloc failed in netsnmp_baby_steps_handler_get\n"); 00096 netsnmp_handler_free(mh); 00097 mh = NULL; 00098 } 00099 else { 00100 md->refcnt = 1; 00101 mh->myvoid = md; 00102 mh->data_clone = (void *(*)(void *))netsnmp_baby_steps_modes_ref; 00103 mh->data_free = (void (*)(void *))netsnmp_baby_steps_modes_deref; 00104 if (0 == modes) 00105 modes = BABY_STEP_ALL; 00106 md->registered = modes; 00107 } 00108 00109 /* 00110 * don't set MIB_HANDLER_AUTO_NEXT, since we need to call lower 00111 * handlers with a munged mode. 00112 */ 00113 00114 return mh; 00115 } 00116 00118 static int 00119 _baby_steps_helper(netsnmp_mib_handler *handler, 00120 netsnmp_handler_registration *reginfo, 00121 netsnmp_agent_request_info *reqinfo, 00122 netsnmp_request_info *requests) 00123 { 00124 netsnmp_baby_steps_modes *bs_modes; 00125 int save_mode, i, rc = SNMP_ERR_NOERROR; 00126 u_short *mode_map_ptr; 00127 00128 DEBUGMSGTL(("baby_steps", "Got request, mode %s\n", 00129 se_find_label_in_slist("agent_mode",reqinfo->mode))); 00130 00131 bs_modes = (netsnmp_baby_steps_modes*)handler->myvoid; 00132 netsnmp_assert(NULL != bs_modes); 00133 00134 switch (reqinfo->mode) { 00135 00136 #ifndef NETSNMP_NO_WRITE_SUPPORT 00137 case MODE_SET_RESERVE1: 00138 /* 00139 * clear completed modes 00140 * xxx-rks: this will break for pdus with set requests to different 00141 * rows in the same table when the handler is set up to use the row 00142 * merge helper as well (or if requests are serialized). 00143 */ 00144 bs_modes->completed = 0; 00147 case MODE_SET_RESERVE2: 00148 case MODE_SET_ACTION: 00149 case MODE_SET_COMMIT: 00150 case MODE_SET_FREE: 00151 case MODE_SET_UNDO: 00152 mode_map_ptr = set_mode_map[reqinfo->mode]; 00153 break; 00154 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 00155 00156 default: 00157 /* 00158 * clear completed modes 00159 */ 00160 bs_modes->completed = 0; 00161 00162 mode_map_ptr = get_mode_map; 00163 } 00164 00165 /* 00166 * NOTE: if you update this chart, please update the versions in 00167 * local/mib2c-conf.d/parent-set.m2i 00168 * agent/mibgroup/helpers/baby_steps.c 00169 * while you're at it. 00170 */ 00171 /* 00172 *********************************************************************** 00173 * Baby Steps Flow Chart (2004.06.05) * 00174 * * 00175 * +--------------+ +================+ U = unconditional path * 00176 * |optional state| ||required state|| S = path for success * 00177 * +--------------+ +================+ E = path for error * 00178 *********************************************************************** 00179 * 00180 * +--------------+ 00181 * | pre | 00182 * | request | 00183 * +--------------+ 00184 * | U 00185 * +-------------+ +==============+ 00186 * | row |f|<-------|| object || 00187 * | create |1| E || lookup || 00188 * +-------------+ +==============+ 00189 * E | | S | S 00190 * | +------------------>| 00191 * | +==============+ 00192 * | E || check || 00193 * |<---------------|| values || 00194 * | +==============+ 00195 * | | S 00196 * | +==============+ 00197 * | +<-------|| undo || 00198 * | | E || setup || 00199 * | | +==============+ 00200 * | | | S 00201 * | | +==============+ 00202 * | | || set ||-------------------------->+ 00203 * | | || value || E | 00204 * | | +==============+ | 00205 * | | | S | 00206 * | | +--------------+ | 00207 * | | | check |-------------------------->| 00208 * | | | consistency | E | 00209 * | | +--------------+ | 00210 * | | | S | 00211 * | | +==============+ +==============+ | 00212 * | | || commit ||-------->|| undo || | 00213 * | | || || E || commit || | 00214 * | | +==============+ +==============+ | 00215 * | | | S U |<--------+ 00216 * | | +--------------+ +==============+ 00217 * | | | irreversible | || undo || 00218 * | | | commit | || set || 00219 * | | +--------------+ +==============+ 00220 * | | | U U | 00221 * | +-------------->|<------------------------+ 00222 * | +==============+ 00223 * | || undo || 00224 * | || cleanup || 00225 * | +==============+ 00226 * +---------------------->| U 00227 * | 00228 * (err && f1)------------------->+ 00229 * | | 00230 * +--------------+ +--------------+ 00231 * | post |<--------| row | 00232 * | request | U | release | 00233 * +--------------+ +--------------+ 00234 * 00235 */ 00236 /* 00237 * save original mode 00238 */ 00239 save_mode = reqinfo->mode; 00240 for(i = 0; i < BABY_STEPS_PER_MODE_MAX; ++i ) { 00241 /* 00242 * break if we run out of baby steps for this mode 00243 */ 00244 if(mode_map_ptr[i] == BABY_STEP_NONE) 00245 break; 00246 00247 DEBUGMSGTL(("baby_steps", " baby step mode %s\n", 00248 se_find_label_in_slist("babystep_mode",mode_map_ptr[i]))); 00249 00250 /* 00251 * skip modes the handler didn't register for 00252 */ 00253 if (BSTEP_USE_ORIGINAL != mode_map_ptr[i]) { 00254 u_int mode_flag; 00255 00256 #ifndef NETSNMP_NO_WRITE_SUPPORT 00257 /* 00258 * skip undo commit if commit wasn't hit, and 00259 * undo_cleanup if undo_setup wasn't hit. 00260 */ 00261 if((MODE_SET_UNDO == save_mode) && 00262 (MODE_BSTEP_UNDO_COMMIT == mode_map_ptr[i]) && 00263 !(BABY_STEP_COMMIT & bs_modes->completed)) { 00264 DEBUGMSGTL(("baby_steps", 00265 " skipping commit undo (no commit)\n")); 00266 continue; 00267 } 00268 else if((MODE_SET_FREE == save_mode) && 00269 (MODE_BSTEP_UNDO_CLEANUP == mode_map_ptr[i]) && 00270 !(BABY_STEP_UNDO_SETUP & bs_modes->completed)) { 00271 DEBUGMSGTL(("baby_steps", 00272 " skipping undo cleanup (no undo setup)\n")); 00273 continue; 00274 } 00275 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 00276 00277 reqinfo->mode = mode_map_ptr[i]; 00278 mode_flag = netsnmp_baby_step_mode2flag( mode_map_ptr[i] ); 00279 if((mode_flag & bs_modes->registered)) 00280 bs_modes->completed |= mode_flag; 00281 else { 00282 DEBUGMSGTL(("baby_steps", 00283 " skipping mode (not registered)\n")); 00284 continue; 00285 } 00286 00287 00288 } 00289 else { 00290 reqinfo->mode = save_mode; 00291 } 00292 00293 #ifdef BABY_STEPS_NEXT_MODE 00294 /* 00295 * I can't remember why I wanted the next mode in the request, 00296 * but it's not used anywhere, so don't use this code. saved, 00297 * in case I remember why I thought needed it. - rstory 040911 00298 */ 00299 if((BABY_STEPS_PER_MODE_MAX - 1) == i) 00300 reqinfo->next_mode_ok = BABY_STEP_NONE; 00301 else { 00302 if(BSTEP_USE_ORIGINAL == mode_map_ptr[i+1]) 00303 reqinfo->next_mode_ok = save_mode; 00304 else 00305 reqinfo->next_mode_ok = mode_map_ptr[i+1]; 00306 } 00307 #endif 00308 00309 /* 00310 * call handlers for baby step 00311 */ 00312 rc = netsnmp_call_next_handler(handler, reginfo, reqinfo, 00313 requests); 00314 00315 /* 00316 * check for error calling handler (unlikely, but...) 00317 */ 00318 if(rc) { 00319 DEBUGMSGTL(("baby_steps", " ERROR:handler error\n")); 00320 break; 00321 } 00322 00323 /* 00324 * check for errors in any of the requests for GET-like, reserve1, 00325 * reserve2 and action. (there is no recovery from errors 00326 * in commit, free or undo.) 00327 */ 00328 if (MODE_IS_GET(save_mode) 00329 #ifndef NETSNMP_NO_WRITE_SUPPORT 00330 || (save_mode < SNMP_MSG_INTERNAL_SET_COMMIT) 00331 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 00332 ) { 00333 rc = netsnmp_check_requests_error(requests); 00334 if(rc) { 00335 DEBUGMSGTL(("baby_steps", " ERROR:request error\n")); 00336 break; 00337 } 00338 } 00339 } 00340 00341 /* 00342 * restore original mode 00343 */ 00344 reqinfo->mode = save_mode; 00345 00346 00347 return rc; 00348 } 00349 00354 netsnmp_feature_child_of(netsnmp_baby_steps_handler_init,netsnmp_unused) 00355 #ifndef NETSNMP_FEATURE_REMOVE_NETSNMP_BABY_STEPS_HANDLER_INIT 00356 void 00357 netsnmp_baby_steps_handler_init(void) 00358 { 00359 netsnmp_register_handler_by_name("baby_steps", 00360 netsnmp_baby_steps_handler_get(BABY_STEP_ALL)); 00361 } 00362 #endif /* NETSNMP_FEATURE_REMOVE_NETSNMP_BABY_STEPS_HANDLER_INIT */ 00363 00374 netsnmp_mib_handler * 00375 netsnmp_baby_steps_access_multiplexer_get(netsnmp_baby_steps_access_methods *am) 00376 { 00377 netsnmp_mib_handler *mh; 00378 00379 mh = netsnmp_create_handler("baby_steps_mux", 00380 _baby_steps_access_multiplexer); 00381 if(!mh) 00382 return NULL; 00383 00384 mh->myvoid = am; 00385 mh->flags |= MIB_HANDLER_AUTO_NEXT; 00386 00387 return mh; 00388 } 00389 00391 static int 00392 _baby_steps_access_multiplexer(netsnmp_mib_handler *handler, 00393 netsnmp_handler_registration *reginfo, 00394 netsnmp_agent_request_info *reqinfo, 00395 netsnmp_request_info *requests) 00396 { 00397 void *temp_void; 00398 Netsnmp_Node_Handler *method = NULL; 00399 netsnmp_baby_steps_access_methods *access_methods; 00400 int rc = SNMP_ERR_NOERROR; 00401 00403 netsnmp_assert((handler!=NULL) && (reginfo!=NULL) && (reqinfo!=NULL) && 00404 (requests!=NULL)); 00405 00406 DEBUGMSGT(("baby_steps_mux", "mode %s\n", 00407 se_find_label_in_slist("babystep_mode",reqinfo->mode))); 00408 00409 access_methods = (netsnmp_baby_steps_access_methods *)handler->myvoid; 00410 if(!access_methods) { 00411 snmp_log(LOG_ERR,"baby_steps_access_multiplexer has no methods\n"); 00412 return SNMPERR_GENERR; 00413 } 00414 00415 switch(reqinfo->mode) { 00416 00417 case MODE_BSTEP_PRE_REQUEST: 00418 if( access_methods->pre_request ) 00419 method = access_methods->pre_request; 00420 break; 00421 00422 case MODE_BSTEP_OBJECT_LOOKUP: 00423 if( access_methods->object_lookup ) 00424 method = access_methods->object_lookup; 00425 break; 00426 00427 case SNMP_MSG_GET: 00428 case SNMP_MSG_GETNEXT: 00429 if( access_methods->get_values ) 00430 method = access_methods->get_values; 00431 break; 00432 00433 #ifndef NETSNMP_NO_WRITE_SUPPORT 00434 case MODE_BSTEP_CHECK_VALUE: 00435 if( access_methods->object_syntax_checks ) 00436 method = access_methods->object_syntax_checks; 00437 break; 00438 00439 case MODE_BSTEP_ROW_CREATE: 00440 if( access_methods->row_creation ) 00441 method = access_methods->row_creation; 00442 break; 00443 00444 case MODE_BSTEP_UNDO_SETUP: 00445 if( access_methods->undo_setup ) 00446 method = access_methods->undo_setup; 00447 break; 00448 00449 case MODE_BSTEP_SET_VALUE: 00450 if( access_methods->set_values ) 00451 method = access_methods->set_values; 00452 break; 00453 00454 case MODE_BSTEP_CHECK_CONSISTENCY: 00455 if( access_methods->consistency_checks ) 00456 method = access_methods->consistency_checks; 00457 break; 00458 00459 case MODE_BSTEP_UNDO_SET: 00460 if( access_methods->undo_sets ) 00461 method = access_methods->undo_sets; 00462 break; 00463 00464 case MODE_BSTEP_COMMIT: 00465 if( access_methods->commit ) 00466 method = access_methods->commit; 00467 break; 00468 00469 case MODE_BSTEP_UNDO_COMMIT: 00470 if( access_methods->undo_commit ) 00471 method = access_methods->undo_commit; 00472 break; 00473 00474 case MODE_BSTEP_IRREVERSIBLE_COMMIT: 00475 if( access_methods->irreversible_commit ) 00476 method = access_methods->irreversible_commit; 00477 break; 00478 00479 case MODE_BSTEP_UNDO_CLEANUP: 00480 if( access_methods->undo_cleanup ) 00481 method = access_methods->undo_cleanup; 00482 break; 00483 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 00484 00485 case MODE_BSTEP_POST_REQUEST: 00486 if( access_methods->post_request ) 00487 method = access_methods->post_request; 00488 break; 00489 00490 default: 00491 snmp_log(LOG_ERR,"unknown mode %d\n", reqinfo->mode); 00492 return SNMP_ERR_GENERR; 00493 } 00494 00495 /* 00496 * if method exists, set up handler void and call method. 00497 */ 00498 if(NULL != method) { 00499 temp_void = handler->myvoid; 00500 handler->myvoid = access_methods->my_access_void; 00501 rc = (*method)(handler, reginfo, reqinfo, requests); 00502 handler->myvoid = temp_void; 00503 } 00504 else { 00505 rc = SNMP_ERR_GENERR; 00506 snmp_log(LOG_ERR,"baby steps multiplexer handler called for a mode " 00507 "with no handler\n"); 00508 netsnmp_assert(NULL != method); 00509 } 00510 00511 /* 00512 * don't call any lower handlers, it will be done for us 00513 * since we set MIB_HANDLER_AUTO_NEXT 00514 */ 00515 00516 return rc; 00517 } 00518 00519 /* 00520 * give a baby step mode, return the flag for that mode 00521 */ 00522 int 00523 netsnmp_baby_step_mode2flag( u_int mode ) 00524 { 00525 switch( mode ) { 00526 case MODE_BSTEP_OBJECT_LOOKUP: 00527 return BABY_STEP_OBJECT_LOOKUP; 00528 #ifndef NETSNMP_NO_WRITE_SUPPORT 00529 case MODE_BSTEP_SET_VALUE: 00530 return BABY_STEP_SET_VALUE; 00531 case MODE_BSTEP_IRREVERSIBLE_COMMIT: 00532 return BABY_STEP_IRREVERSIBLE_COMMIT; 00533 case MODE_BSTEP_CHECK_VALUE: 00534 return BABY_STEP_CHECK_VALUE; 00535 case MODE_BSTEP_PRE_REQUEST: 00536 return BABY_STEP_PRE_REQUEST; 00537 case MODE_BSTEP_POST_REQUEST: 00538 return BABY_STEP_POST_REQUEST; 00539 case MODE_BSTEP_UNDO_SETUP: 00540 return BABY_STEP_UNDO_SETUP; 00541 case MODE_BSTEP_UNDO_CLEANUP: 00542 return BABY_STEP_UNDO_CLEANUP; 00543 case MODE_BSTEP_UNDO_SET: 00544 return BABY_STEP_UNDO_SET; 00545 case MODE_BSTEP_ROW_CREATE: 00546 return BABY_STEP_ROW_CREATE; 00547 case MODE_BSTEP_CHECK_CONSISTENCY: 00548 return BABY_STEP_CHECK_CONSISTENCY; 00549 case MODE_BSTEP_COMMIT: 00550 return BABY_STEP_COMMIT; 00551 case MODE_BSTEP_UNDO_COMMIT: 00552 return BABY_STEP_UNDO_COMMIT; 00553 #endif /* NETSNMP_NO_WRITE_SUPPORT */ 00554 default: 00555 netsnmp_assert("unknown flag"); 00556 break; 00557 } 00558 return 0; 00559 } 00562 #else /* NETSNMP_FEATURE_REMOVE_BABY_STEPS */ 00563 netsnmp_feature_unused(baby_steps); 00564 #endif /* NETSNMP_FEATURE_REMOVE_BABY_STEPS */ 00565