1 /*
2 * Portions of this file are subject to the following copyright(s). See
3 * the Net-SNMP's COPYING file for more details and other copyrights
4 * that may apply:
5 *
6 * Portions of this file are copyrighted by:
7 * Copyright (c) 2016 VMware, Inc. All rights reserved.
8 * Use is subject to license terms specified in the COPYING file
9 * distributed with the Net-SNMP package.
10 */
11
12 #include <net-snmp/net-snmp-config.h>
13 #include <net-snmp/net-snmp-features.h>
14
15 #include <net-snmp/net-snmp-includes.h>
16 #include <net-snmp/agent/net-snmp-agent-includes.h>
17
18 #include <net-snmp/agent/table_tdata.h>
19
20 #if HAVE_STRING_H
21 #include <string.h>
22 #else
23 #include <strings.h>
24 #endif
25
26 #include <net-snmp/agent/table.h>
27 #include <net-snmp/agent/table_container.h>
28 #include <net-snmp/agent/read_only.h>
29
30 netsnmp_feature_child_of(table_tdata_all, mib_helpers);
31 netsnmp_feature_child_of(table_tdata, table_tdata_all);
32 netsnmp_feature_child_of(table_tdata_delete_table, table_tdata_all);
33 netsnmp_feature_child_of(table_tdata_extract_table, table_tdata_all);
34 netsnmp_feature_child_of(table_tdata_remove_row, table_tdata_all);
35 netsnmp_feature_child_of(table_tdata_insert_row, table_tdata_all);
36
37 #ifdef NETSNMP_FEATURE_REQUIRE_TABLE_TDATA
38 netsnmp_feature_require(table_container_row_insert);
39 #ifdef NETSNMP_FEATURE_REQUIRE_TABLE_TDATA_REMOVE_ROW
40 netsnmp_feature_require(table_container_row_remove);
41 #endif /* NETSNMP_FEATURE_REQUIRE_TABLE_TDATA_REMOVE_ROW */
42 #endif /* NETSNMP_FEATURE_REQUIRE_TABLE_TDATA */
43
44 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA
45
46 /** @defgroup tdata tdata
47 * Implement a table with datamatted storage.
48 * @ingroup table
49 *
50 * This helper helps you implement a table where all the rows are
51 * expected to be stored within the agent itself and not in some
52 * external storage location. It can be used to store a list of
53 * rows, where a row consists of the indexes to the table and a
54 * generic data pointer. You can then implement a subhandler which
55 * is passed the exact row definition and data it must return data
56 * for or accept data for. Complex GETNEXT handling is greatly
57 * simplified in this case.
58 *
59 * @{
60 */
61
62 /* ==================================
63 *
64 * TData API: Table maintenance
65 *
66 * ================================== */
67
68 /*
69 * generates the index portion of an table oid from a varlist.
70 */
71 void
_netsnmp_tdata_generate_index_oid(netsnmp_tdata_row * row)72 _netsnmp_tdata_generate_index_oid(netsnmp_tdata_row *row)
73 {
74 build_oid(&row->oid_index.oids, &row->oid_index.len, NULL, 0, row->indexes);
75 }
76
77 /** creates and returns a 'tdata' table data structure */
78 netsnmp_tdata *
netsnmp_tdata_create_table(const char * name,long flags)79 netsnmp_tdata_create_table(const char *name, long flags)
80 {
81 netsnmp_tdata *table = SNMP_MALLOC_TYPEDEF(netsnmp_tdata);
82 if ( !table )
83 return NULL;
84
85 table->flags = flags;
86 if (name)
87 table->name = strdup(name);
88
89 if (!(table->flags & TDATA_FLAG_NO_CONTAINER)) {
90 table->container = netsnmp_container_find( name );
91 if (!table->container)
92 table->container = netsnmp_container_find( "table_container" );
93 if (table->container && name)
94 table->container->container_name = strdup(name);
95 }
96 return table;
97 }
98
99 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_DELETE_TABLE
100 /** creates and returns a 'tdata' table data structure */
101 void
netsnmp_tdata_delete_table(netsnmp_tdata * table)102 netsnmp_tdata_delete_table(netsnmp_tdata *table)
103 {
104 if (!table)
105 return;
106
107 if (table->name)
108 free(table->name);
109 if (table->container)
110 CONTAINER_FREE(table->container);
111
112 SNMP_FREE(table);
113 return;
114 }
115 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_DELETE_TABLE */
116
117 /** creates and returns a pointer to new row data structure */
118 netsnmp_tdata_row *
netsnmp_tdata_create_row(void)119 netsnmp_tdata_create_row(void)
120 {
121 netsnmp_tdata_row *row = SNMP_MALLOC_TYPEDEF(netsnmp_tdata_row);
122 return row;
123 }
124
125 /** clones a 'tdata' row. DOES NOT CLONE THE TABLE-SPECIFIC ENTRY DATA. */
126 netsnmp_feature_child_of(tdata_clone_row, table_tdata_all);
127 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_CLONE_ROW
128 netsnmp_tdata_row *
netsnmp_tdata_clone_row(netsnmp_tdata_row * row)129 netsnmp_tdata_clone_row(netsnmp_tdata_row *row)
130 {
131 netsnmp_tdata_row *newrow = NULL;
132 if (!row)
133 return NULL;
134
135 newrow = netsnmp_memdup(row, sizeof(netsnmp_tdata_row));
136 if (!newrow)
137 return NULL;
138
139 if (row->indexes) {
140 newrow->indexes = snmp_clone_varbind(newrow->indexes);
141 if (!newrow->indexes) {
142 SNMP_FREE(newrow);
143 return NULL;
144 }
145 }
146
147 if (row->oid_index.oids) {
148 newrow->oid_index.oids =
149 snmp_duplicate_objid(row->oid_index.oids, row->oid_index.len);
150 if (!newrow->oid_index.oids) {
151 if (newrow->indexes)
152 snmp_free_varbind(newrow->indexes);
153 SNMP_FREE(newrow);
154 return NULL;
155 }
156 }
157
158 return newrow;
159 }
160 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_CLONE_ROW */
161
162 /** copy the contents of a 'tdata' row.
163 DOES NOT COPY THE TABLE-SPECIFIC ENTRY DATA. */
164 netsnmp_feature_child_of(tdata_copy_row, table_tdata_all);
165 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_COPY_ROW
166 int
netsnmp_tdata_copy_row(netsnmp_tdata_row * dst_row,netsnmp_tdata_row * src_row)167 netsnmp_tdata_copy_row(netsnmp_tdata_row *dst_row, netsnmp_tdata_row *src_row)
168 {
169 if ( !src_row || !dst_row )
170 return -1;
171
172 memcpy((u_char *) dst_row, (u_char *) src_row,
173 sizeof(netsnmp_tdata_row));
174 if (src_row->indexes) {
175 dst_row->indexes = snmp_clone_varbind(src_row->indexes);
176 if (!dst_row->indexes)
177 return -1;
178 }
179
180 if (src_row->oid_index.oids) {
181 dst_row->oid_index.oids = snmp_duplicate_objid(src_row->oid_index.oids,
182 src_row->oid_index.len);
183 if (!dst_row->oid_index.oids)
184 return -1;
185 }
186
187 return 0;
188 }
189 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_COPY_ROW */
190
191 /** deletes the memory used by the specified row
192 * returns the table-specific entry data
193 * (that it doesn't know how to delete) */
194 void *
netsnmp_tdata_delete_row(netsnmp_tdata_row * row)195 netsnmp_tdata_delete_row(netsnmp_tdata_row *row)
196 {
197 void *data;
198
199 if (!row)
200 return NULL;
201
202 /*
203 * free the memory we can
204 */
205 if (row->indexes)
206 snmp_free_varbind(row->indexes);
207 SNMP_FREE(row->oid_index.oids);
208 data = row->data;
209 free(row);
210
211 /*
212 * return the void * pointer
213 */
214 return data;
215 }
216
217 /**
218 * Adds a row to the given table (stored in proper lexographical order).
219 *
220 * returns SNMPERR_SUCCESS on successful addition.
221 * or SNMPERR_GENERR on failure (E.G., indexes already existed)
222 */
223 int
netsnmp_tdata_add_row(netsnmp_tdata * table,netsnmp_tdata_row * row)224 netsnmp_tdata_add_row(netsnmp_tdata *table,
225 netsnmp_tdata_row *row)
226 {
227 if (!row || !table)
228 return SNMPERR_GENERR;
229
230 if (row->indexes)
231 _netsnmp_tdata_generate_index_oid(row);
232
233 if (!row->oid_index.oids) {
234 snmp_log(LOG_ERR,
235 "illegal data attempted to be added to table %s (no index)\n",
236 table->name);
237 return SNMPERR_GENERR;
238 }
239
240 /*
241 * The individual index values probably won't be needed,
242 * so this memory can be released.
243 * Note that this is purely internal to the helper.
244 * The calling application can set this flag as
245 * a hint to the helper that these values aren't
246 * required, but it's up to the helper as to
247 * whether it takes any notice or not!
248 */
249 if (table->flags & TDATA_FLAG_NO_STORE_INDEXES) {
250 snmp_free_varbind(row->indexes);
251 row->indexes = NULL;
252 }
253
254 /*
255 * add this row to the stored table
256 */
257 if (CONTAINER_INSERT( table->container, row ) != 0)
258 return SNMPERR_GENERR;
259
260 DEBUGMSGTL(("tdata_add_row", "added row (%p)\n", row));
261
262 return SNMPERR_SUCCESS;
263 }
264
265 /** swaps out origrow with newrow. This does *not* delete/free anything! */
266 netsnmp_feature_child_of(tdata_replace_row, table_tdata_all);
267 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_REPLACE_ROW
268 void
netsnmp_tdata_replace_row(netsnmp_tdata * table,netsnmp_tdata_row * origrow,netsnmp_tdata_row * newrow)269 netsnmp_tdata_replace_row(netsnmp_tdata *table,
270 netsnmp_tdata_row *origrow,
271 netsnmp_tdata_row *newrow)
272 {
273 netsnmp_tdata_remove_row(table, origrow);
274 netsnmp_tdata_add_row(table, newrow);
275 }
276 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_REPLACE_ROW */
277
278 /**
279 * removes a row from the given table and returns it (no free's called)
280 *
281 * returns the row pointer itself on successful removing.
282 * or NULL on failure (bad arguments)
283 */
284 netsnmp_tdata_row *
netsnmp_tdata_remove_row(netsnmp_tdata * table,netsnmp_tdata_row * row)285 netsnmp_tdata_remove_row(netsnmp_tdata *table,
286 netsnmp_tdata_row *row)
287 {
288 if (!row || !table)
289 return NULL;
290
291 CONTAINER_REMOVE( table->container, row );
292 return row;
293 }
294
295 /**
296 * removes and frees a row of the given table and
297 * returns the table-specific entry data
298 *
299 * returns the void * pointer on successful deletion.
300 * or NULL on failure (bad arguments)
301 */
302 void *
netsnmp_tdata_remove_and_delete_row(netsnmp_tdata * table,netsnmp_tdata_row * row)303 netsnmp_tdata_remove_and_delete_row(netsnmp_tdata *table,
304 netsnmp_tdata_row *row)
305 {
306 if (!row || !table)
307 return NULL;
308
309 /*
310 * remove it from the list
311 */
312 netsnmp_tdata_remove_row(table, row);
313 return netsnmp_tdata_delete_row(row);
314 }
315
316
317 /* ==================================
318 *
319 * TData API: MIB maintenance
320 *
321 * ================================== */
322
323 Netsnmp_Node_Handler _netsnmp_tdata_helper_handler;
324
325 /** Creates a tdata handler and returns it */
326 netsnmp_mib_handler *
netsnmp_get_tdata_handler(netsnmp_tdata * table)327 netsnmp_get_tdata_handler(netsnmp_tdata *table)
328 {
329 netsnmp_mib_handler *ret = NULL;
330
331 if (!table) {
332 snmp_log(LOG_INFO,
333 "netsnmp_get_tdata_handler(NULL) called\n");
334 return NULL;
335 }
336
337 ret = netsnmp_create_handler(TABLE_TDATA_NAME,
338 _netsnmp_tdata_helper_handler);
339 if (ret) {
340 ret->flags |= MIB_HANDLER_AUTO_NEXT;
341 ret->myvoid = (void *) table;
342 }
343 return ret;
344 }
345
346 /*
347 * The helper handler that takes care of passing a specific row of
348 * data down to the lower handler(s). The table_container helper
349 * has already taken care of identifying the appropriate row of the
350 * table (and converting GETNEXT requests into an equivalent GET request)
351 * So all we need to do here is make sure that the row is accessible
352 * using tdata-style retrieval techniques as well.
353 */
354 int
_netsnmp_tdata_helper_handler(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)355 _netsnmp_tdata_helper_handler(netsnmp_mib_handler *handler,
356 netsnmp_handler_registration *reginfo,
357 netsnmp_agent_request_info *reqinfo,
358 netsnmp_request_info *requests)
359 {
360 netsnmp_tdata *table = (netsnmp_tdata *) handler->myvoid;
361 netsnmp_request_info *request;
362 netsnmp_table_request_info *table_info;
363 netsnmp_tdata_row *row;
364 int need_processing;
365
366 switch ( reqinfo->mode ) {
367 case MODE_GET:
368 #ifndef NETSNMP_NO_WRITE_SUPPORT
369 case MODE_SET_RESERVE1:
370 #endif /* NETSNMP_NO_WRITE_SUPPORT */
371
372 need_processing = reqinfo->mode == MODE_GET ? 0 : 1;
373 for (request = requests; request; request = request->next) {
374 if (request->processed)
375 continue;
376
377 table_info = netsnmp_extract_table_info(request);
378 if (!table_info) {
379 netsnmp_assert(table_info); /* yes, this will always hit */
380 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
381 continue; /* eek */
382 }
383 row = (netsnmp_tdata_row*)netsnmp_container_table_row_extract( request );
384 if (!row && (reqinfo->mode == MODE_GET)) {
385 netsnmp_assert(row); /* yes, this will always hit */
386 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
387 continue; /* eek */
388 }
389 ++need_processing;
390 netsnmp_request_add_list_data(request,
391 netsnmp_create_data_list(
392 TABLE_TDATA_TABLE, table, NULL));
393 netsnmp_request_add_list_data(request,
394 netsnmp_create_data_list(
395 TABLE_TDATA_ROW, row, NULL));
396 }
397 /** skip next handler if processing not needed */
398 if (!need_processing)
399 handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
400 }
401
402 /* next handler called automatically - 'AUTO_NEXT' */
403 return SNMP_ERR_NOERROR;
404 }
405
406
407 /** registers a tdata-based MIB table */
408 int
netsnmp_tdata_register(netsnmp_handler_registration * reginfo,netsnmp_tdata * table,netsnmp_table_registration_info * table_info)409 netsnmp_tdata_register(netsnmp_handler_registration *reginfo,
410 netsnmp_tdata *table,
411 netsnmp_table_registration_info *table_info)
412 {
413 netsnmp_mib_handler *handler = netsnmp_get_tdata_handler(table);
414
415 if (!reginfo || !table || !table_info || !handler ||
416 (netsnmp_inject_handler(reginfo, handler) != SNMPERR_SUCCESS)) {
417 snmp_log(LOG_ERR, "could not create tdata handler\n");
418 netsnmp_handler_free(handler);
419 netsnmp_handler_registration_free(reginfo);
420 return SNMP_ERR_GENERR;
421 }
422
423 return netsnmp_container_table_register(reginfo, table_info,
424 table->container, TABLE_CONTAINER_KEY_NETSNMP_INDEX);
425 }
426
427 netsnmp_feature_child_of(tdata_unregister, table_tdata_all);
428 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_UNREGISTER
429 int
netsnmp_tdata_unregister(netsnmp_handler_registration * reginfo)430 netsnmp_tdata_unregister(netsnmp_handler_registration *reginfo)
431 {
432 /* free table; */
433 return netsnmp_container_table_unregister(reginfo);
434 }
435 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_UNREGISTER */
436
437 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_EXTRACT_TABLE
438 /** extracts the tdata table from the request structure */
439 netsnmp_tdata *
netsnmp_tdata_extract_table(netsnmp_request_info * request)440 netsnmp_tdata_extract_table(netsnmp_request_info *request)
441 {
442 return (netsnmp_tdata *) netsnmp_request_get_list_data(request,
443 TABLE_TDATA_TABLE);
444 }
445 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_EXTRACT_TABLE */
446
447 /** extracts the tdata container from the request structure */
448 netsnmp_feature_child_of(tdata_extract_container, table_tdata_all);
449 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_EXTRACT_CONTAINER
450 netsnmp_container *
netsnmp_tdata_extract_container(netsnmp_request_info * request)451 netsnmp_tdata_extract_container(netsnmp_request_info *request)
452 {
453 netsnmp_tdata *tdata = (netsnmp_tdata*)
454 netsnmp_request_get_list_data(request, TABLE_TDATA_TABLE);
455 return ( tdata ? tdata->container : NULL );
456 }
457 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_EXTRACT_CONTAINER */
458
459 /** extracts the tdata row being accessed from the request structure */
460 netsnmp_tdata_row *
netsnmp_tdata_extract_row(netsnmp_request_info * request)461 netsnmp_tdata_extract_row(netsnmp_request_info *request)
462 {
463 return (netsnmp_tdata_row *) netsnmp_container_table_row_extract(request);
464 }
465
466 /** extracts the (table-specific) entry being accessed from the
467 * request structure */
468 void *
netsnmp_tdata_extract_entry(netsnmp_request_info * request)469 netsnmp_tdata_extract_entry(netsnmp_request_info *request)
470 {
471 netsnmp_tdata_row *row =
472 (netsnmp_tdata_row *) netsnmp_tdata_extract_row(request);
473 if (row)
474 return row->data;
475 else
476 return NULL;
477 }
478
479 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_INSERT_ROW
480 /** inserts a newly created tdata row into a request */
481 NETSNMP_INLINE void
netsnmp_insert_tdata_row(netsnmp_request_info * request,netsnmp_tdata_row * row)482 netsnmp_insert_tdata_row(netsnmp_request_info *request,
483 netsnmp_tdata_row *row)
484 {
485 netsnmp_container_table_row_insert(request, (netsnmp_index *)row);
486 }
487 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_INSERT_ROW */
488
489 #ifndef NETSNMP_FEATURE_REMOVE_TABLE_TDATA_REMOVE_ROW
490 /** inserts a newly created tdata row into a request */
491 NETSNMP_INLINE void
netsnmp_remove_tdata_row(netsnmp_request_info * request,netsnmp_tdata_row * row)492 netsnmp_remove_tdata_row(netsnmp_request_info *request,
493 netsnmp_tdata_row *row)
494 {
495 netsnmp_container_table_row_remove(request, (netsnmp_index *)row);
496 }
497 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA_REMOVE_ROW */
498
499
500 /* ==================================
501 *
502 * Generic API: Row operations
503 *
504 * ================================== */
505
506 /** returns the (table-specific) entry data for a given row */
507 void *
netsnmp_tdata_row_entry(netsnmp_tdata_row * row)508 netsnmp_tdata_row_entry( netsnmp_tdata_row *row )
509 {
510 if (row)
511 return row->data;
512 else
513 return NULL;
514 }
515
516 /** returns the first row in the table */
517 netsnmp_tdata_row *
netsnmp_tdata_row_first(netsnmp_tdata * table)518 netsnmp_tdata_row_first(netsnmp_tdata *table)
519 {
520 return (netsnmp_tdata_row *)CONTAINER_FIRST( table->container );
521 }
522
523 /** finds a row in the 'tdata' table given another row */
524 netsnmp_tdata_row *
netsnmp_tdata_row_get(netsnmp_tdata * table,netsnmp_tdata_row * row)525 netsnmp_tdata_row_get( netsnmp_tdata *table,
526 netsnmp_tdata_row *row)
527 {
528 return (netsnmp_tdata_row*)CONTAINER_FIND( table->container, row );
529 }
530
531 /** returns the next row in the table */
532 netsnmp_tdata_row *
netsnmp_tdata_row_next(netsnmp_tdata * table,netsnmp_tdata_row * row)533 netsnmp_tdata_row_next( netsnmp_tdata *table,
534 netsnmp_tdata_row *row)
535 {
536 return (netsnmp_tdata_row *)CONTAINER_NEXT( table->container, row );
537 }
538
539 /** finds a row in the 'tdata' table given the index values */
540 netsnmp_tdata_row *
netsnmp_tdata_row_get_byidx(netsnmp_tdata * table,netsnmp_variable_list * indexes)541 netsnmp_tdata_row_get_byidx(netsnmp_tdata *table,
542 netsnmp_variable_list *indexes)
543 {
544 oid searchfor[ MAX_OID_LEN];
545 size_t searchfor_len = MAX_OID_LEN;
546
547 build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
548 indexes);
549 return netsnmp_tdata_row_get_byoid(table, searchfor, searchfor_len);
550 }
551
552 /** finds a row in the 'tdata' table given the index OID */
553 netsnmp_tdata_row *
netsnmp_tdata_row_get_byoid(netsnmp_tdata * table,oid * searchfor,size_t searchfor_len)554 netsnmp_tdata_row_get_byoid(netsnmp_tdata *table,
555 oid * searchfor, size_t searchfor_len)
556 {
557 netsnmp_index index;
558 if (!table)
559 return NULL;
560
561 index.oids = searchfor;
562 index.len = searchfor_len;
563 return (netsnmp_tdata_row*)CONTAINER_FIND( table->container, &index );
564 }
565
566 /** finds the lexically next row in the 'tdata' table
567 given the index values */
568 netsnmp_tdata_row *
netsnmp_tdata_row_next_byidx(netsnmp_tdata * table,netsnmp_variable_list * indexes)569 netsnmp_tdata_row_next_byidx(netsnmp_tdata *table,
570 netsnmp_variable_list *indexes)
571 {
572 oid searchfor[ MAX_OID_LEN];
573 size_t searchfor_len = MAX_OID_LEN;
574
575 build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
576 indexes);
577 return netsnmp_tdata_row_next_byoid(table, searchfor, searchfor_len);
578 }
579
580 /** finds the lexically next row in the 'tdata' table
581 given the index OID */
582 netsnmp_tdata_row *
netsnmp_tdata_row_next_byoid(netsnmp_tdata * table,oid * searchfor,size_t searchfor_len)583 netsnmp_tdata_row_next_byoid(netsnmp_tdata *table,
584 oid * searchfor, size_t searchfor_len)
585 {
586 netsnmp_index index;
587 if (!table)
588 return NULL;
589
590 index.oids = searchfor;
591 index.len = searchfor_len;
592 return (netsnmp_tdata_row*)CONTAINER_NEXT( table->container, &index );
593 }
594
595 netsnmp_feature_child_of(tdata_row_count, table_tdata_all);
596 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_ROW_COUNT
597 int
netsnmp_tdata_row_count(netsnmp_tdata * table)598 netsnmp_tdata_row_count(netsnmp_tdata *table)
599 {
600 if (!table)
601 return 0;
602 return CONTAINER_SIZE( table->container );
603 }
604 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_ROW_COUNT */
605
606 /* ==================================
607 *
608 * Generic API: Index operations on a 'tdata' table
609 *
610 * ================================== */
611
612
613 /** compare a row with the given index values */
614 netsnmp_feature_child_of(tdata_compare_idx, table_tdata_all);
615 #ifndef NETSNMP_FEATURE_REMOVE_TDATA_COMPARE_IDX
616 int
netsnmp_tdata_compare_idx(netsnmp_tdata_row * row,netsnmp_variable_list * indexes)617 netsnmp_tdata_compare_idx(netsnmp_tdata_row *row,
618 netsnmp_variable_list *indexes)
619 {
620 oid searchfor[ MAX_OID_LEN];
621 size_t searchfor_len = MAX_OID_LEN;
622
623 build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
624 indexes);
625 return netsnmp_tdata_compare_oid(row, searchfor, searchfor_len);
626 }
627 #endif /* NETSNMP_FEATURE_REMOVE_TDATA_COMPARE_IDX */
628
629 /** compare a row with the given index OID */
630 int
netsnmp_tdata_compare_oid(netsnmp_tdata_row * row,oid * compareto,size_t compareto_len)631 netsnmp_tdata_compare_oid(netsnmp_tdata_row *row,
632 oid * compareto, size_t compareto_len)
633 {
634 netsnmp_index *index = (netsnmp_index *)row;
635 return snmp_oid_compare( index->oids, index->len,
636 compareto, compareto_len);
637 }
638
639 int
netsnmp_tdata_compare_subtree_idx(netsnmp_tdata_row * row,netsnmp_variable_list * indexes)640 netsnmp_tdata_compare_subtree_idx(netsnmp_tdata_row *row,
641 netsnmp_variable_list *indexes)
642 {
643 oid searchfor[ MAX_OID_LEN];
644 size_t searchfor_len = MAX_OID_LEN;
645
646 build_oid_noalloc(searchfor, MAX_OID_LEN, &searchfor_len, NULL, 0,
647 indexes);
648 return netsnmp_tdata_compare_subtree_oid(row, searchfor, searchfor_len);
649 }
650
651 int
netsnmp_tdata_compare_subtree_oid(netsnmp_tdata_row * row,oid * compareto,size_t compareto_len)652 netsnmp_tdata_compare_subtree_oid(netsnmp_tdata_row *row,
653 oid * compareto, size_t compareto_len)
654 {
655 netsnmp_index *index = (netsnmp_index *)row;
656 return snmp_oidtree_compare( index->oids, index->len,
657 compareto, compareto_len);
658 }
659 #else /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA */
660 netsnmp_feature_unused(table_tdata);
661 #endif /* NETSNMP_FEATURE_REMOVE_TABLE_TDATA */
662
663
664 /** @}
665 */
666