1 #include <net-snmp/net-snmp-config.h>
2 #include <net-snmp/net-snmp-features.h>
3 #include <net-snmp/net-snmp-includes.h>
4 #include <net-snmp/agent/net-snmp-agent-includes.h>
5 #include <net-snmp/agent/scalar.h>
6
7 #ifdef HAVE_STRING_H
8 #include <string.h>
9 #else
10 #include <strings.h>
11 #endif
12
13 #include <net-snmp/agent/cache_handler.h>
14 #include "agent/nsCache.h"
15
16 netsnmp_feature_require(cache_get_head);
17
18
19 /*
20 * use unadvertised function to get cache head. You really should not
21 * do this, since the internal storage mechanism might change.
22 */
23 extern netsnmp_cache *netsnmp_cache_get_head(void);
24
25
26 #define nsCache 1, 3, 6, 1, 4, 1, 8072, 1, 5
27
28 /*
29 * OIDs for the cacheging control scalar objects
30 *
31 * Note that these we're registering the full object rather
32 * than the (sole) valid instance in each case, in order
33 * to handle requests for invalid instances properly.
34 */
35
36 /*
37 * ... and for the cache table.
38 */
39
40 #define NSCACHE_TIMEOUT 2
41 #define NSCACHE_STATUS 3
42
43 #define NSCACHE_STATUS_ENABLED 1
44 #define NSCACHE_STATUS_DISABLED 2
45 #define NSCACHE_STATUS_EMPTY 3
46 #define NSCACHE_STATUS_ACTIVE 4
47 #define NSCACHE_STATUS_EXPIRED 5
48
49 NETSNMP_IMPORT struct snmp_alarm *
50 sa_find_specific(unsigned int clientreg);
51
52
53 void
init_nsCache(void)54 init_nsCache(void)
55 {
56 const oid nsCacheTimeout_oid[] = { nsCache, 1 };
57 const oid nsCacheEnabled_oid[] = { nsCache, 2 };
58 const oid nsCacheTable_oid[] = { nsCache, 3 };
59
60 netsnmp_table_registration_info *table_info;
61 netsnmp_iterator_info *iinfo;
62
63 /*
64 * Register the scalar objects...
65 */
66 DEBUGMSGTL(("nsCacheScalars", "Initializing\n"));
67 netsnmp_register_scalar(
68 netsnmp_create_handler_registration(
69 "nsCacheTimeout", handle_nsCacheTimeout,
70 nsCacheTimeout_oid, OID_LENGTH(nsCacheTimeout_oid),
71 HANDLER_CAN_RWRITE)
72 );
73 netsnmp_register_scalar(
74 netsnmp_create_handler_registration(
75 "nsCacheEnabled", handle_nsCacheEnabled,
76 nsCacheEnabled_oid, OID_LENGTH(nsCacheEnabled_oid),
77 HANDLER_CAN_RWRITE)
78 );
79
80 /*
81 * ... and the table.
82 * We need to define the column structure and indexing....
83 */
84
85 table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
86 if (!table_info) {
87 return;
88 }
89 netsnmp_table_helper_add_indexes(table_info, ASN_PRIV_IMPLIED_OBJECT_ID, 0);
90 table_info->min_column = NSCACHE_TIMEOUT;
91 table_info->max_column = NSCACHE_STATUS;
92
93
94 /*
95 * .... and the iteration information ....
96 */
97 iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
98 if (!iinfo) {
99 SNMP_FREE(table_info);
100 return;
101 }
102 iinfo->get_first_data_point = get_first_cache_entry;
103 iinfo->get_next_data_point = get_next_cache_entry;
104 iinfo->table_reginfo = table_info;
105
106
107 /*
108 * .... and register the table with the agent.
109 */
110 netsnmp_register_table_iterator2(
111 netsnmp_create_handler_registration(
112 "tzCacheTable", handle_nsCacheTable,
113 nsCacheTable_oid, OID_LENGTH(nsCacheTable_oid),
114 HANDLER_CAN_RWRITE),
115 iinfo);
116 }
117
118
119 /*
120 * nsCache scalar handling
121 */
122
123 int
handle_nsCacheTimeout(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)124 handle_nsCacheTimeout(netsnmp_mib_handler *handler,
125 netsnmp_handler_registration *reginfo,
126 netsnmp_agent_request_info *reqinfo,
127 netsnmp_request_info *requests)
128 {
129 long cache_default_timeout =
130 netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
131 NETSNMP_DS_AGENT_CACHE_TIMEOUT);
132 netsnmp_request_info *request=NULL;
133
134 switch (reqinfo->mode) {
135
136 case MODE_GET:
137 for (request = requests; request; request=request->next) {
138 snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
139 (u_char*)&cache_default_timeout,
140 sizeof(cache_default_timeout));
141 }
142 break;
143
144
145 #ifndef NETSNMP_NO_WRITE_SUPPORT
146 case MODE_SET_RESERVE1:
147 for (request = requests; request; request=request->next) {
148 if ( request->status != 0 ) {
149 return SNMP_ERR_NOERROR; /* Already got an error */
150 }
151 if ( request->requestvb->type != ASN_INTEGER ) {
152 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
153 return SNMP_ERR_WRONGTYPE;
154 }
155 if ( *request->requestvb->val.integer < 0 ) {
156 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
157 return SNMP_ERR_WRONGVALUE;
158 }
159 }
160 break;
161
162 case MODE_SET_COMMIT:
163 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
164 NETSNMP_DS_AGENT_CACHE_TIMEOUT,
165 *requests->requestvb->val.integer);
166 break;
167 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
168 }
169
170 return SNMP_ERR_NOERROR;
171 }
172
173
174 int
handle_nsCacheEnabled(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)175 handle_nsCacheEnabled(netsnmp_mib_handler *handler,
176 netsnmp_handler_registration *reginfo,
177 netsnmp_agent_request_info *reqinfo,
178 netsnmp_request_info *requests)
179 {
180 long enabled;
181 netsnmp_request_info *request=NULL;
182
183 switch (reqinfo->mode) {
184
185 case MODE_GET:
186 enabled = (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
187 NETSNMP_DS_AGENT_NO_CACHING)
188 ? NSCACHE_STATUS_ENABLED /* Actually True/False */
189 : NSCACHE_STATUS_DISABLED );
190 for (request = requests; request; request=request->next) {
191 snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
192 (u_char*)&enabled, sizeof(enabled));
193 }
194 break;
195
196
197 #ifndef NETSNMP_NO_WRITE_SUPPORT
198 case MODE_SET_RESERVE1:
199 for (request = requests; request; request=request->next) {
200 if ( request->status != 0 ) {
201 return SNMP_ERR_NOERROR; /* Already got an error */
202 }
203 if ( request->requestvb->type != ASN_INTEGER ) {
204 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
205 return SNMP_ERR_WRONGTYPE;
206 }
207 if ((*request->requestvb->val.integer != NSCACHE_STATUS_ENABLED) &&
208 (*request->requestvb->val.integer != NSCACHE_STATUS_DISABLED)) {
209 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
210 return SNMP_ERR_WRONGVALUE;
211 }
212 }
213 break;
214
215 case MODE_SET_COMMIT:
216 enabled = *requests->requestvb->val.integer;
217 if (enabled == NSCACHE_STATUS_DISABLED)
218 enabled = 0;
219 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
220 NETSNMP_DS_AGENT_NO_CACHING, enabled);
221 break;
222 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
223 }
224
225 return SNMP_ERR_NOERROR;
226 }
227
228
229 /*
230 * nsCacheTable handling
231 */
232
233 netsnmp_variable_list *
get_first_cache_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)234 get_first_cache_entry(void **loop_context, void **data_context,
235 netsnmp_variable_list *index,
236 netsnmp_iterator_info *data)
237 {
238 netsnmp_cache *cache_head = netsnmp_cache_get_head();
239
240 if ( !cache_head )
241 return NULL;
242
243 snmp_set_var_value(index, (u_char*)cache_head->rootoid,
244 sizeof(oid) * cache_head->rootoid_len);
245 *loop_context = (void*)cache_head;
246 *data_context = (void*)cache_head;
247 return index;
248 }
249
250 netsnmp_variable_list *
get_next_cache_entry(void ** loop_context,void ** data_context,netsnmp_variable_list * index,netsnmp_iterator_info * data)251 get_next_cache_entry(void **loop_context, void **data_context,
252 netsnmp_variable_list *index,
253 netsnmp_iterator_info *data)
254 {
255 netsnmp_cache *cache = (netsnmp_cache *)*loop_context;
256 cache = cache->next;
257
258 if ( !cache )
259 return NULL;
260
261 snmp_set_var_value(index, (u_char*)cache->rootoid,
262 sizeof(oid) * cache->rootoid_len);
263 *loop_context = (void*)cache;
264 *data_context = (void*)cache;
265 return index;
266 }
267
268
269 int
handle_nsCacheTable(netsnmp_mib_handler * handler,netsnmp_handler_registration * reginfo,netsnmp_agent_request_info * reqinfo,netsnmp_request_info * requests)270 handle_nsCacheTable(netsnmp_mib_handler *handler,
271 netsnmp_handler_registration *reginfo,
272 netsnmp_agent_request_info *reqinfo,
273 netsnmp_request_info *requests)
274 {
275 long status;
276 netsnmp_request_info *request = NULL;
277 netsnmp_table_request_info *table_info = NULL;
278 netsnmp_cache *cache_entry = NULL;
279
280 switch (reqinfo->mode) {
281
282 case MODE_GET:
283 for (request=requests; request; request=request->next) {
284 if (request->processed != 0)
285 continue;
286
287 cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request);
288 table_info = netsnmp_extract_table_info(request);
289
290 switch (table_info->colnum) {
291 case NSCACHE_TIMEOUT:
292 if (!cache_entry) {
293 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
294 continue;
295 }
296 status = cache_entry->timeout;
297 snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
298 (u_char*)&status, sizeof(status));
299 break;
300
301 case NSCACHE_STATUS:
302 if (!cache_entry) {
303 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
304 continue;
305 }
306 status = (cache_entry->enabled ?
307 (cache_entry->timestampM ?
308 (cache_entry->timeout >= 0 &&
309 !netsnmp_ready_monotonic(cache_entry->timestampM,
310 1000*cache_entry->timeout) ?
311 NSCACHE_STATUS_ACTIVE:
312 NSCACHE_STATUS_EXPIRED) :
313 NSCACHE_STATUS_EMPTY) :
314 NSCACHE_STATUS_DISABLED);
315 snmp_set_var_typed_value(request->requestvb, ASN_INTEGER,
316 (u_char*)&status, sizeof(status));
317 break;
318
319 default:
320 netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT);
321 continue;
322 }
323 }
324 break;
325
326
327 #ifndef NETSNMP_NO_WRITE_SUPPORT
328 case MODE_SET_RESERVE1:
329 for (request=requests; request; request=request->next) {
330 if (request->processed != 0)
331 continue;
332 if ( request->status != 0 ) {
333 return SNMP_ERR_NOERROR; /* Already got an error */
334 }
335 cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request);
336 table_info = netsnmp_extract_table_info(request);
337
338 switch (table_info->colnum) {
339 case NSCACHE_TIMEOUT:
340 if (!cache_entry) {
341 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
342 return SNMP_ERR_NOCREATION;
343 }
344 if ( request->requestvb->type != ASN_INTEGER ) {
345 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
346 return SNMP_ERR_WRONGTYPE;
347 }
348 if (*request->requestvb->val.integer < 0 ) {
349 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
350 return SNMP_ERR_WRONGVALUE;
351 }
352 break;
353
354 case NSCACHE_STATUS:
355 if (!cache_entry) {
356 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
357 return SNMP_ERR_NOCREATION;
358 }
359 if ( request->requestvb->type != ASN_INTEGER ) {
360 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
361 return SNMP_ERR_WRONGTYPE;
362 }
363 status = *request->requestvb->val.integer;
364 if (!((status == NSCACHE_STATUS_ENABLED ) ||
365 (status == NSCACHE_STATUS_DISABLED ) ||
366 (status == NSCACHE_STATUS_EMPTY ))) {
367 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE);
368 return SNMP_ERR_WRONGVALUE;
369 }
370 break;
371
372 default:
373 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
374 return SNMP_ERR_NOCREATION; /* XXX - is this right ? */
375 }
376 }
377 break;
378
379
380 case MODE_SET_COMMIT:
381 for (request=requests; request; request=request->next) {
382 if (request->processed != 0)
383 continue;
384 if ( request->status != 0 ) {
385 return SNMP_ERR_NOERROR; /* Already got an error */
386 }
387 cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request);
388 if (!cache_entry) {
389 netsnmp_set_request_error(reqinfo, request, SNMP_ERR_COMMITFAILED);
390 return SNMP_ERR_COMMITFAILED; /* Shouldn't happen! */
391 }
392 table_info = netsnmp_extract_table_info(request);
393
394 switch (table_info->colnum) {
395 case NSCACHE_TIMEOUT:
396 cache_entry->timeout = *request->requestvb->val.integer;
397 /*
398 * check for auto repeat
399 */
400 if (cache_entry->timer_id) {
401 struct snmp_alarm * sa =
402 sa_find_specific(cache_entry->timer_id);
403 if (NULL != sa)
404 sa->t.tv_sec = cache_entry->timeout;
405 }
406 break;
407
408 case NSCACHE_STATUS:
409 switch (*request->requestvb->val.integer) {
410 case NSCACHE_STATUS_ENABLED:
411 cache_entry->enabled = 1;
412 break;
413 case NSCACHE_STATUS_DISABLED:
414 cache_entry->enabled = 0;
415 break;
416 case NSCACHE_STATUS_EMPTY:
417 cache_entry->free_cache(cache_entry, cache_entry->magic);
418 free(cache_entry->timestampM);
419 cache_entry->timestampM = NULL;
420 break;
421 }
422 break;
423 }
424 }
425 break;
426 #endif /* !NETSNMP_NO_WRITE_SUPPORT */
427 }
428
429 return SNMP_ERR_NOERROR;
430 }
431