00001
00002
00003
00004
00005
00006 #include <net-snmp/net-snmp-config.h>
00007
00008 #if HAVE_STRING_H
00009 #include <string.h>
00010 #else
00011 #include <strings.h>
00012 #endif
00013
00014 #include <net-snmp/net-snmp-includes.h>
00015 #include <net-snmp/agent/net-snmp-agent-includes.h>
00016
00017 #include <net-snmp/agent/table.h>
00018 #include <net-snmp/agent/table_array.h>
00019 #include <net-snmp/library/container.h>
00020 #include <net-snmp/library/snmp_assert.h>
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 static const char *mode_name[] = {
00033 "Reserve 1",
00034 "Reserve 2",
00035 "Action",
00036 "Commit",
00037 "Free",
00038 "Undo"
00039 };
00040
00041
00042
00043
00044 typedef struct table_container_data_s {
00045
00047 netsnmp_table_registration_info *tblreg_info;
00048
00050 netsnmp_container *table;
00051
00052
00053
00054
00055
00058 int group_rows;
00059
00061 netsnmp_table_array_callbacks *cb;
00062
00063 } table_container_data;
00064
00134
00135
00136
00137
00138
00139
00140
00141
00142
00148 int
00149 netsnmp_table_container_register(netsnmp_handler_registration *reginfo,
00150 netsnmp_table_registration_info *tabreg,
00151 netsnmp_table_array_callbacks *cb,
00152 netsnmp_container *container,
00153 int group_rows)
00154 {
00155 table_container_data *tad = SNMP_MALLOC_TYPEDEF(table_container_data);
00156 if (!tad)
00157 return SNMPERR_GENERR;
00158 tad->tblreg_info = tabreg;
00159
00160 if (!cb) {
00161 snmp_log(LOG_ERR, "table_array registration with no callbacks\n" );
00162 free(tad);
00163 return SNMPERR_GENERR;
00164 }
00165
00166
00167
00168 if ((cb->can_set &&
00169 ((NULL==cb->duplicate_row) || (NULL==cb->delete_row) ||
00170 (NULL==cb->row_copy)) )) {
00171 snmp_log(LOG_ERR, "table_array registration with incomplete "
00172 "callback structure.\n");
00173 free(tad);
00174 return SNMPERR_GENERR;
00175 }
00176
00177 if (NULL==container) {
00178 tad->table = netsnmp_container_find("table_array");
00179 snmp_log(LOG_ERR, "table_array couldn't allocate container\n" );
00180 free(tad);
00181 return SNMPERR_GENERR;
00182 } else
00183 tad->table = container;
00184 if (NULL==tad->table->compare)
00185 tad->table->compare = netsnmp_compare_netsnmp_index;
00186 if (NULL==tad->table->ncompare)
00187 tad->table->ncompare = netsnmp_ncompare_netsnmp_index;
00188
00189 tad->cb = cb;
00190
00191 reginfo->handler->myvoid = tad;
00192
00193 return netsnmp_register_table(reginfo, tabreg);
00194 }
00195
00196 int
00197 netsnmp_table_array_register(netsnmp_handler_registration *reginfo,
00198 netsnmp_table_registration_info *tabreg,
00199 netsnmp_table_array_callbacks *cb,
00200 netsnmp_container *container,
00201 int group_rows)
00202 {
00203 netsnmp_inject_handler(reginfo,
00204 netsnmp_create_handler(reginfo->handlerName,
00205 netsnmp_table_array_helper_handler));
00206 return netsnmp_table_container_register(reginfo, tabreg, cb,
00207 container, group_rows);
00208 }
00209
00211 netsnmp_mib_handler *
00212 netsnmp_find_table_array_handler(netsnmp_handler_registration *reginfo)
00213 {
00214 netsnmp_mib_handler *mh;
00215 if (!reginfo)
00216 return NULL;
00217 mh = reginfo->handler;
00218 while (mh) {
00219 if (mh->access_method == netsnmp_table_array_helper_handler)
00220 break;
00221 mh = mh->next;
00222 }
00223
00224 return mh;
00225 }
00226
00228 netsnmp_container *
00229 netsnmp_extract_array_context(netsnmp_request_info *request)
00230 {
00231 return netsnmp_request_get_list_data(request, TABLE_ARRAY_NAME);
00232 }
00233
00235 int
00236 netsnmp_table_array_check_row_status(netsnmp_table_array_callbacks *cb,
00237 netsnmp_request_group *ag,
00238 long *rs_new, long *rs_old)
00239 {
00240 netsnmp_index *row_ctx;
00241 netsnmp_index *undo_ctx;
00242 if (!ag || !cb)
00243 return SNMPERR_GENERR;
00244 row_ctx = ag->existing_row;
00245 undo_ctx = ag->undo_info;
00246
00247
00248
00249
00250 if (row_ctx) {
00251
00252
00253
00254
00255
00256
00257 if (RS_IS_GOING_ACTIVE(*rs_new)) {
00258
00259
00260
00261 if ((NULL==cb->can_activate) ||
00262 cb->can_activate(undo_ctx, row_ctx, ag))
00263 *rs_new = RS_ACTIVE;
00264 else
00265 return SNMP_ERR_INCONSISTENTVALUE;
00266 } else {
00267
00268
00269
00270 if (undo_ctx) {
00271
00272
00273
00274 if (RS_IS_ACTIVE(*rs_old)) {
00275
00276
00277
00278 if (cb->can_deactivate &&
00279 !cb->can_deactivate(undo_ctx, row_ctx, ag)) {
00280 return SNMP_ERR_INCONSISTENTVALUE;
00281 }
00282 }
00283 } else {
00284
00285
00286
00287 }
00288
00289 if (*rs_new != RS_DESTROY) {
00290 if ((NULL==cb->can_activate) ||
00291 cb->can_activate(undo_ctx, row_ctx, ag))
00292 *rs_new = RS_NOTINSERVICE;
00293 else
00294 *rs_new = RS_NOTREADY;
00295 } else {
00296 if (cb->can_delete && !cb->can_delete(undo_ctx, row_ctx, ag)) {
00297 return SNMP_ERR_INCONSISTENTVALUE;
00298 }
00299 ag->row_deleted = 1;
00300 }
00301 }
00302 } else {
00303
00304
00305
00306 if (cb->can_delete && !cb->can_delete(undo_ctx, row_ctx, ag)) {
00307 return SNMP_ERR_INCONSISTENTVALUE;
00308 }
00309 }
00310
00311 return SNMP_ERR_NOERROR;
00312 }
00313
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 typedef struct set_context_s {
00348 netsnmp_agent_request_info *agtreq_info;
00349 table_container_data *tad;
00350 int status;
00351 } set_context;
00352
00353 static void
00354 release_netsnmp_request_group(netsnmp_index *g, void *v)
00355 {
00356 netsnmp_request_group_item *tmp;
00357 netsnmp_request_group *group = (netsnmp_request_group *) g;
00358
00359 if (!g)
00360 return;
00361 while (group->list) {
00362 tmp = group->list;
00363 group->list = tmp->next;
00364 free(tmp);
00365 }
00366
00367 free(group);
00368 }
00369
00370 static void
00371 release_netsnmp_request_groups(void *vp)
00372 {
00373 netsnmp_container *c = (netsnmp_container*)vp;
00374 CONTAINER_FOR_EACH(c, (netsnmp_container_obj_func*)
00375 release_netsnmp_request_group, NULL);
00376 CONTAINER_FREE(c);
00377 }
00378
00379 void
00380 build_new_oid(netsnmp_handler_registration *reginfo,
00381 netsnmp_table_request_info *tblreq_info,
00382 netsnmp_index *row, netsnmp_request_info *current)
00383 {
00384 oid coloid[MAX_OID_LEN];
00385 int coloid_len;
00386
00387 if (!tblreq_info || !reginfo || !row || !current)
00388 return;
00389
00390 coloid_len = reginfo->rootoid_len + 2;
00391 memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
00392
00394 coloid[reginfo->rootoid_len] = 1;
00395
00397 coloid[reginfo->rootoid_len + 1] = tblreq_info->colnum;
00398
00400 memcpy(&coloid[reginfo->rootoid_len + 2], row->oids,
00401 row->len * sizeof(oid));
00402
00403 snmp_set_var_objid(current->requestvb, coloid,
00404 reginfo->rootoid_len + 2 + row->len);
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 int
00417 process_get_requests(netsnmp_handler_registration *reginfo,
00418 netsnmp_agent_request_info *agtreq_info,
00419 netsnmp_request_info *requests,
00420 table_container_data * tad)
00421 {
00422 int rc = SNMP_ERR_NOERROR;
00423 netsnmp_request_info *current;
00424 netsnmp_index *row = NULL;
00425 netsnmp_table_request_info *tblreq_info;
00426 netsnmp_variable_list *var;
00427
00428
00429
00430
00431
00432 for (current = requests; current; current = current->next) {
00433
00434 var = current->requestvb;
00435 DEBUGMSGTL(("table_array:get",
00436 " process_get_request oid:"));
00437 DEBUGMSGOID(("table_array:get", var->name,
00438 var->name_length));
00439 DEBUGMSG(("table_array:get", "\n"));
00440
00441
00442
00443
00444 if (current->processed != 0) {
00445 DEBUGMSGTL(("table_array:get", "already processed\n"));
00446 continue;
00447 }
00448
00449
00450
00451
00452
00453
00454
00455 tblreq_info = netsnmp_extract_table_info(current);
00456 netsnmp_assert(tblreq_info->colnum <= tad->tblreg_info->max_column);
00457
00458 if ((agtreq_info->mode == MODE_GETNEXT) ||
00459 (agtreq_info->mode == MODE_GETBULK)) {
00460
00461
00462
00463 row = netsnmp_table_index_find_next_row(tad->table, tblreq_info);
00464 if (!row) {
00465
00466
00467
00468
00469
00470
00471 DEBUGMSGTL(("table_array:get", "no row found\n"));
00472 netsnmp_set_request_error(agtreq_info, current,
00473 SNMP_ENDOFMIBVIEW);
00474 continue;
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485 build_new_oid(reginfo, tblreq_info, row, current);
00486
00487 }
00488 else {
00489 netsnmp_index index;
00490 index.oids = tblreq_info->index_oid;
00491 index.len = tblreq_info->index_oid_len;
00492
00493 row = CONTAINER_FIND(tad->table, &index);
00494 if (!row) {
00495 DEBUGMSGTL(("table_array:get", "no row found\n"));
00496 netsnmp_set_request_error(agtreq_info, current,
00497 SNMP_NOSUCHINSTANCE);
00498 continue;
00499 }
00500 }
00502
00503
00504
00505 rc = tad->cb->get_value(current, row, tblreq_info);
00506
00507 }
00509 return rc;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522 void
00523 group_requests(netsnmp_agent_request_info *agtreq_info,
00524 netsnmp_request_info *requests,
00525 netsnmp_container *request_group, table_container_data * tad)
00526 {
00527 netsnmp_table_request_info *tblreq_info;
00528 netsnmp_variable_list *var;
00529 netsnmp_index *row, *tmp, index;
00530 netsnmp_request_info *current;
00531 netsnmp_request_group *g;
00532 netsnmp_request_group_item *i;
00533
00534 for (current = requests; current; current = current->next) {
00535
00536 var = current->requestvb;
00537
00538
00539
00540
00541 if (current->processed != 0) {
00542 DEBUGMSGTL(("table_array:group",
00543 "already processed\n"));
00544 continue;
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555 row = NULL;
00556 tblreq_info = netsnmp_extract_table_info(current);
00557 netsnmp_assert(tblreq_info->colnum <= tad->tblreg_info->max_column);
00558
00559
00560
00561
00562 index.oids = tblreq_info->index_oid;
00563 index.len = tblreq_info->index_oid_len;
00564 tmp = CONTAINER_FIND(request_group, &index);
00565 if (tmp) {
00566 DEBUGMSGTL(("table_array:group",
00567 " existing group:"));
00568 DEBUGMSGOID(("table_array:group", index.oids,
00569 index.len));
00570 DEBUGMSG(("table_array:group", "\n"));
00571 g = (netsnmp_request_group *) tmp;
00572 i = SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item);
00573 i->ri = current;
00574 i->tri = tblreq_info;
00575 i->next = g->list;
00576 g->list = i;
00577
00579 continue;
00580 }
00581
00582 DEBUGMSGTL(("table_array:group", " new group"));
00583 DEBUGMSGOID(("table_array:group", index.oids,
00584 index.len));
00585 DEBUGMSG(("table_array:group", "\n"));
00586 g = SNMP_MALLOC_TYPEDEF(netsnmp_request_group);
00587 i = SNMP_MALLOC_TYPEDEF(netsnmp_request_group_item);
00588 g->list = i;
00589 g->table = tad->table;
00590 i->ri = current;
00591 i->tri = tblreq_info;
00594
00595
00596
00597
00598 row = g->existing_row = CONTAINER_FIND(tad->table, &index);
00599 if (!g->existing_row) {
00600 if (!tad->cb->create_row) {
00601 if(MODE_IS_SET(agtreq_info->mode))
00602 netsnmp_set_request_error(agtreq_info, current,
00603 SNMP_ERR_NOTWRITABLE);
00604 else
00605 netsnmp_set_request_error(agtreq_info, current,
00606 SNMP_NOSUCHINSTANCE);
00607 free(g);
00608 free(i);
00609 continue;
00610 }
00612 row = g->existing_row = tad->cb->create_row(&index);
00613 if (!row) {
00614
00615
00616 netsnmp_set_request_error(agtreq_info, current,
00617 SNMP_ERR_GENERR);
00618 free(g);
00619 free(i);
00620 continue;
00621 }
00622 g->row_created = 1;
00623 }
00624
00625 g->index.oids = row->oids;
00626 g->index.len = row->len;
00627
00628 CONTAINER_INSERT(request_group, g);
00629
00630 }
00631 }
00632
00633 static void
00634 process_set_group(netsnmp_index *o, void *c)
00635 {
00636
00637 set_context *context = (set_context *) c;
00638 netsnmp_request_group *ag = (netsnmp_request_group *) o;
00639 int rc = SNMP_ERR_NOERROR;
00640
00641 switch (context->agtreq_info->mode) {
00642
00643 case MODE_SET_RESERVE1:
00645
00646
00647
00648 if (ag->row_created == 0) {
00649 if (context->tad->cb->duplicate_row)
00650 ag->undo_info = context->tad->cb->duplicate_row(ag->existing_row);
00651 else
00652 ag->undo_info = NULL;
00653 if (NULL == ag->undo_info) {
00654 rc = SNMP_ERR_RESOURCEUNAVAILABLE;
00655 break;
00656 }
00657 }
00658
00659 if (context->tad->cb->set_reserve1)
00660 context->tad->cb->set_reserve1(ag);
00661 break;
00662
00663 case MODE_SET_RESERVE2:
00664 if (context->tad->cb->set_reserve2)
00665 context->tad->cb->set_reserve2(ag);
00666 break;
00667
00668 case MODE_SET_ACTION:
00669 if (context->tad->cb->set_action)
00670 context->tad->cb->set_action(ag);
00671 break;
00672
00673 case MODE_SET_COMMIT:
00674 if (ag->row_created == 0) {
00675
00676
00677
00678 if (ag->row_deleted == 1) {
00679 DEBUGMSGT((TABLE_ARRAY_NAME, "action: deleting row\n"));
00680 if (CONTAINER_REMOVE(ag->table, ag->existing_row) != 0) {
00681 rc = SNMP_ERR_COMMITFAILED;
00682 break;
00683 }
00684 }
00685 } else if (ag->row_deleted == 0) {
00686
00687
00688
00689 DEBUGMSGT((TABLE_ARRAY_NAME, "action: inserting row\n"));
00690 if (CONTAINER_INSERT(ag->table, ag->existing_row) != 0) {
00691 rc = SNMP_ERR_COMMITFAILED;
00692 break;
00693 }
00694 }
00695
00696 if (context->tad->cb->set_commit)
00697 context->tad->cb->set_commit(ag);
00698
00700 if (ag->undo_info) {
00701 context->tad->cb->delete_row(ag->undo_info);
00702 ag->undo_info = NULL;
00703 }
00704
00705 #if 0
00706
00707
00708
00709
00710 if (context->tad->notifications) {
00711 if (ag->undo_info) {
00712 if (!ag->existing_row)
00713 netsnmp_monitor_notify(EVENT_ROW_DEL);
00714 else
00715 netsnmp_monitor_notify(EVENT_ROW_MOD);
00716 }
00717 else
00718 netsnmp_monitor_notify(EVENT_ROW_ADD);
00719 }
00720 #endif
00721
00722 if ((ag->row_created == 0) && (ag->row_deleted == 1)) {
00723 context->tad->cb->delete_row(ag->existing_row);
00724 ag->existing_row = NULL;
00725 }
00726 break;
00727
00728 case MODE_SET_FREE:
00729 if (context->tad->cb->set_free)
00730 context->tad->cb->set_free(ag);
00731
00733 if (ag->row_created == 1) {
00734 if (context->tad->cb->delete_row)
00735 context->tad->cb->delete_row(ag->existing_row);
00736 ag->existing_row = NULL;
00737 }
00738 else {
00739 if (context->tad->cb->delete_row)
00740 context->tad->cb->delete_row(ag->undo_info);
00741 ag->undo_info = NULL;
00742 }
00743 break;
00744
00745 case MODE_SET_UNDO:
00746
00747
00748
00749 if (context->tad->cb->set_undo)
00750 context->tad->cb->set_undo(ag);
00751
00752
00753
00754
00755 if (ag->row_created == 0) {
00756
00757
00758
00759 context->tad->cb->row_copy(ag->existing_row, ag->undo_info);
00760 context->tad->cb->delete_row(ag->undo_info);
00761 ag->undo_info = NULL;
00762 }
00763 else {
00764 context->tad->cb->delete_row(ag->existing_row);
00765 ag->existing_row = NULL;
00766 }
00767 break;
00768
00769 default:
00770 snmp_log(LOG_ERR, "unknown mode processing SET for "
00771 "netsnmp_table_array_helper_handler\n");
00772 rc = SNMP_ERR_GENERR;
00773 break;
00774 }
00775
00776 if (rc)
00777 netsnmp_set_request_error(context->agtreq_info,
00778 ag->list->ri, rc);
00779
00780 }
00781
00782 int
00783 process_set_requests(netsnmp_agent_request_info *agtreq_info,
00784 netsnmp_request_info *requests,
00785 table_container_data * tad, char *handler_name)
00786 {
00787 set_context context;
00788 netsnmp_container *request_group;
00789
00790
00791
00792
00793 request_group = (netsnmp_container*) netsnmp_agent_get_list_data
00794 (agtreq_info, handler_name);
00795 if (request_group == NULL) {
00796 netsnmp_data_list *tmp;
00797 request_group = netsnmp_container_find("request_group:"
00798 "table_container");
00799 request_group->compare = netsnmp_compare_netsnmp_index;
00800 request_group->ncompare = netsnmp_ncompare_netsnmp_index;
00801
00802 DEBUGMSGTL(("table_array", "Grouping requests by oid\n"));
00803
00804 tmp = netsnmp_create_data_list(handler_name,
00805 request_group,
00806 release_netsnmp_request_groups);
00807 netsnmp_agent_add_list_data(agtreq_info, tmp);
00808
00809
00810
00811 group_requests(agtreq_info, requests, request_group, tad);
00812 }
00813
00814
00815
00816
00817 context.agtreq_info = agtreq_info;
00818 context.tad = tad;
00819 context.status = SNMP_ERR_NOERROR;
00820 CONTAINER_FOR_EACH(request_group,
00821 (netsnmp_container_obj_func*)process_set_group,
00822 &context);
00823
00824 return context.status;
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837 int
00838 netsnmp_table_array_helper_handler(netsnmp_mib_handler *handler,
00839 netsnmp_handler_registration *reginfo,
00840 netsnmp_agent_request_info *agtreq_info,
00841 netsnmp_request_info *requests)
00842 {
00843
00844
00845
00846
00847
00848
00849
00850 int rc = SNMP_ERR_NOERROR;
00851 table_container_data *tad = (table_container_data *)handler->myvoid;
00852
00853 if (agtreq_info->mode < 0 || agtreq_info->mode > 5) {
00854 DEBUGMSGTL(("table_array", "Mode %d, Got request:\n",
00855 agtreq_info->mode));
00856 } else {
00857 DEBUGMSGTL(("table_array", "Mode %s, Got request:\n",
00858 mode_name[agtreq_info->mode]));
00859 }
00860
00861 if (MODE_IS_SET(agtreq_info->mode)) {
00862
00863
00864
00865 rc = process_set_requests(agtreq_info, requests,
00866 tad, handler->handler_name);
00867
00868
00869
00870 } else
00871 rc = process_get_requests(reginfo, agtreq_info, requests, tad);
00872
00873 if (rc != SNMP_ERR_NOERROR) {
00874 DEBUGMSGTL(("table_array", "processing returned rc %d\n", rc));
00875 }
00876
00877
00878
00879
00880
00881 if (handler->next) {
00882 rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info, requests);
00883 if (rc != SNMP_ERR_NOERROR) {
00884 DEBUGMSGTL(("table_array", "next handler returned rc %d\n", rc));
00885 }
00886 }
00887
00888 return rc;
00889 }