~ubuntu-branches/ubuntu/trusty/net-snmp/trusty

« back to all changes in this revision

Viewing changes to agent/mibgroup/disman/event/mteTrigger.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-05-10 22:20:23 UTC
  • mto: (1.4.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: james.westby@ubuntu.com-20070510222023-3fr07xb9i17xvq32
Tags: upstream-5.3.1
ImportĀ upstreamĀ versionĀ 5.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DisMan Event MIB:
 
3
 *     Core implementation of the trigger handling behaviour
 
4
 */
 
5
 
 
6
#include <net-snmp/net-snmp-config.h>
 
7
#include <net-snmp/net-snmp-includes.h>
 
8
#include <net-snmp/agent/net-snmp-agent-includes.h>
 
9
#include "disman/event/mteTrigger.h"
 
10
#include "disman/event/mteEvent.h"
 
11
 
 
12
netsnmp_tdata *trigger_table_data;
 
13
 
 
14
oid    _sysUpTime_instance[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
 
15
size_t _sysUpTime_inst_len   = OID_LENGTH(_sysUpTime_instance);
 
16
 
 
17
long mteTriggerFailures;
 
18
 
 
19
    /*
 
20
     * Initialize the container for the (combined) mteTrigger*Table,
 
21
     * regardless of which table initialisation routine is called first.
 
22
     */
 
23
 
 
24
void
 
25
init_trigger_table_data(void)
 
26
{
 
27
    DEBUGMSGTL(("disman:event:init", "init trigger container\n"));
 
28
    if (!trigger_table_data) {
 
29
        trigger_table_data = netsnmp_tdata_create_table("mteTriggerTable", 0);
 
30
        if (!trigger_table_data) {
 
31
            snmp_log(LOG_ERR, "failed to create mteTriggerTable");
 
32
            return;
 
33
        }
 
34
        DEBUGMSGTL(("disman:event:init", "create trigger container (%x)\n",
 
35
                                          trigger_table_data));
 
36
    }
 
37
    mteTriggerFailures = 0;
 
38
}
 
39
 
 
40
 
 
41
/** Initializes the mteTrigger module */
 
42
void
 
43
init_mteTrigger(void)
 
44
{
 
45
    init_trigger_table_data();
 
46
 
 
47
}
 
48
 
 
49
    /* ===================================================
 
50
     *
 
51
     * APIs for maintaining the contents of the (combined)
 
52
     *    mteTrigger*Table container.
 
53
     *
 
54
     * =================================================== */
 
55
 
 
56
void
 
57
_mteTrigger_dump(void)
 
58
{
 
59
    struct mteTrigger *entry;
 
60
    netsnmp_tdata_row *row;
 
61
    int i = 0;
 
62
 
 
63
    for (row = netsnmp_tdata_row_first(trigger_table_data);
 
64
         row;
 
65
         row = netsnmp_tdata_row_next(trigger_table_data, row)) {
 
66
        entry = (struct mteTrigger *)row->data;
 
67
        DEBUGMSGTL(("disman:event:dump", "TriggerTable entry %d: ", i));
 
68
        DEBUGMSGOID(("disman:event:dump", row->oid_index.oids, row->oid_index.len));
 
69
        DEBUGMSG(("disman:event:dump", "(%s, %s)",
 
70
                                         row->indexes->val.string,
 
71
                                         row->indexes->next_variable->val.string));
 
72
        DEBUGMSG(("disman:event:dump", ": %x, %x\n", row, entry));
 
73
        i++;
 
74
    }
 
75
    DEBUGMSGTL(("disman:event:dump", "TriggerTable %d entries\n", i));
 
76
}
 
77
 
 
78
 
 
79
/*
 
80
 * Create a new row in the trigger table 
 
81
 */
 
82
netsnmp_tdata_row *
 
83
mteTrigger_createEntry(char *mteOwner, char *mteTName, int fixed)
 
84
{
 
85
    struct mteTrigger *entry;
 
86
    netsnmp_tdata_row *row;
 
87
    size_t mteOwner_len = (mteOwner) ? strlen(mteOwner) : 0;
 
88
    size_t mteTName_len = (mteTName) ? strlen(mteTName) : 0;
 
89
 
 
90
    DEBUGMSGTL(("disman:event:table", "Create trigger entry (%s, %s)\n",
 
91
                                       mteOwner, mteTName));
 
92
    /*
 
93
     * Create the mteTrigger entry, and the
 
94
     * (table-independent) row wrapper structure...
 
95
     */
 
96
    entry = SNMP_MALLOC_TYPEDEF(struct mteTrigger);
 
97
    if (!entry)
 
98
        return NULL;
 
99
 
 
100
    row = netsnmp_tdata_create_row();
 
101
    if (!row) {
 
102
        SNMP_FREE(entry);
 
103
        return NULL;
 
104
    }
 
105
    row->data = entry;
 
106
 
 
107
    /*
 
108
     * ... initialize this row with the indexes supplied
 
109
     *     and the default values for the row...
 
110
     */
 
111
    if (mteOwner)
 
112
        memcpy(entry->mteOwner, mteOwner, mteOwner_len);
 
113
    netsnmp_table_row_add_index(row, ASN_OCTET_STR,
 
114
                                entry->mteOwner, mteOwner_len);
 
115
    if (mteTName)
 
116
        memcpy(entry->mteTName, mteTName, mteTName_len);
 
117
    netsnmp_table_row_add_index(row, ASN_PRIV_IMPLIED_OCTET_STR,
 
118
                                entry->mteTName, mteTName_len);
 
119
 
 
120
 /* entry->mteTriggerTest         = MTE_TRIGGER_BOOLEAN; */
 
121
    entry->mteTriggerValueID_len  = 2;  /* .0.0 */
 
122
    entry->mteTriggerFrequency    = 600;
 
123
    memcpy(entry->mteDeltaDiscontID, _sysUpTime_instance,
 
124
                              sizeof(_sysUpTime_instance));
 
125
    entry->mteDeltaDiscontID_len  =  _sysUpTime_inst_len;
 
126
    entry->mteDeltaDiscontIDType  = MTE_DELTAD_TTICKS;
 
127
    entry->flags                 |= MTE_TRIGGER_FLAG_SYSUPT;
 
128
    entry->mteTExTest             = (MTE_EXIST_PRESENT | MTE_EXIST_ABSENT);
 
129
    entry->mteTExStartup          = (MTE_EXIST_PRESENT | MTE_EXIST_ABSENT);
 
130
    entry->mteTBoolComparison     = MTE_BOOL_UNEQUAL;
 
131
    entry->flags                 |= MTE_TRIGGER_FLAG_BSTART;
 
132
    entry->mteTThStartup          = MTE_THRESH_START_RISEFALL;
 
133
 
 
134
    if (fixed)
 
135
        entry->flags |= MTE_TRIGGER_FLAG_FIXED;
 
136
 
 
137
    /*
 
138
     * ... and insert the row into the (common) table container
 
139
     */
 
140
    netsnmp_tdata_add_row(trigger_table_data, row);
 
141
    DEBUGMSGTL(("disman:event:table", "Trigger entry created\n"));
 
142
    return row;
 
143
}
 
144
 
 
145
/*
 
146
 * Remove a row from the trigger table 
 
147
 */
 
148
void
 
149
mteTrigger_removeEntry(netsnmp_tdata_row *row)
 
150
{
 
151
    struct mteTrigger *entry;
 
152
 
 
153
    if (!row)
 
154
        return;                 /* Nothing to remove */
 
155
    entry = (struct mteTrigger *)
 
156
        netsnmp_tdata_remove_and_delete_row(trigger_table_data, row);
 
157
    if (entry) {
 
158
        mteTrigger_disable( entry );
 
159
        SNMP_FREE(entry);
 
160
    }
 
161
}
 
162
 
 
163
    /* ===================================================
 
164
     *
 
165
     * APIs for evaluating a trigger,
 
166
     *   and firing the appropriate event
 
167
     *
 
168
     * =================================================== */
 
169
const char *_ops[] = { "",
 
170
                "!=", /* MTE_BOOL_UNEQUAL      */
 
171
                "==", /* MTE_BOOL_EQUAL        */
 
172
                "<",  /* MTE_BOOL_LESS         */
 
173
                "<=", /* MTE_BOOL_LESSEQUAL    */
 
174
                ">",  /* MTE_BOOL_GREATER      */
 
175
                ">="  /* MTE_BOOL_GREATEREQUAL */  };
 
176
 
 
177
void
 
178
_mteTrigger_failure( /* int error, */ const char *msg )
 
179
{
 
180
    /*
 
181
     * XXX - Send an mteTriggerFailure trap
 
182
     *           (if configured to do so)
 
183
     */
 
184
    mteTriggerFailures++;
 
185
    snmp_log(LOG_ERR, "%s\n", msg );
 
186
    return;
 
187
}
 
188
 
 
189
void
 
190
mteTrigger_run( unsigned int reg, void *clientarg)
 
191
{
 
192
    struct mteTrigger *entry = (struct mteTrigger *)clientarg;
 
193
    netsnmp_variable_list *var, *vtmp;
 
194
    netsnmp_variable_list *vp1, *vp1_prev;
 
195
    netsnmp_variable_list *vp2, *vp2_prev;
 
196
    netsnmp_variable_list *dvar = NULL;
 
197
    netsnmp_variable_list *dv1  = NULL, *dv2 = NULL;
 
198
    netsnmp_variable_list sysUT_var;
 
199
    int  cmp = 0, n, n2;
 
200
    long value;
 
201
    const char *reason;
 
202
 
 
203
    if (!entry) {
 
204
        snmp_alarm_unregister( reg );
 
205
        return;
 
206
    }
 
207
    if (!(entry->flags & MTE_TRIGGER_FLAG_ENABLED ) ||
 
208
        !(entry->flags & MTE_TRIGGER_FLAG_ACTIVE  ) ||
 
209
        !(entry->flags & MTE_TRIGGER_FLAG_VALID  )) {
 
210
        return;
 
211
    }
 
212
 
 
213
    /*
 
214
     * Retrieve the requested MIB value(s)...
 
215
     */
 
216
    DEBUGMSGTL(( "disman:event:trigger:monitor", "Running trigger (%s)\n", entry->mteTName));
 
217
    var = (netsnmp_variable_list *)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
218
    if (!var) {
 
219
        _mteTrigger_failure("failed to create mteTrigger query varbind");
 
220
        return;
 
221
    }
 
222
    snmp_set_var_objid( var, entry->mteTriggerValueID,
 
223
                             entry->mteTriggerValueID_len );
 
224
    if ( entry->flags & MTE_TRIGGER_FLAG_VWILD ) {
 
225
        n = netsnmp_query_walk( var, entry->session );
 
226
    } else {
 
227
        n = netsnmp_query_get(  var, entry->session );
 
228
    }
 
229
    if ( n != SNMP_ERR_NOERROR ) {
 
230
        DEBUGMSGTL(( "disman:event:trigger:monitor", "Trigger query (%s) failed: %d\n",
 
231
                           (( entry->flags & MTE_TRIGGER_FLAG_VWILD ) ? "walk" : "get"), n));
 
232
        _mteTrigger_failure( "failed to run mteTrigger query" );
 
233
        return;
 
234
    }
 
235
 
 
236
    /*
 
237
     * ... canonicalise the results (to simplify later comparisons)...
 
238
     */
 
239
 
 
240
    vp1 = var;                vp1_prev = NULL;
 
241
    vp2 = entry->old_results; vp2_prev = NULL;
 
242
    entry->count=0;
 
243
    while (vp1) {
 
244
           /*
 
245
            * Flatten various missing values/exceptions into a single form
 
246
            */ 
 
247
        switch (vp1->type) {
 
248
        case SNMP_NOSUCHINSTANCE:
 
249
        case SNMP_NOSUCHOBJECT:
 
250
        case ASN_PRIV_RETRY:   /* Internal only ? */
 
251
            vp1->type = ASN_NULL;
 
252
        }
 
253
           /*
 
254
            * Keep track of how many entries have been retrieved.
 
255
            */ 
 
256
           entry->count++;
 
257
        
 
258
           /*
 
259
            * Ensure previous and current result match
 
260
            *  (with corresponding entries in both lists)
 
261
            * and set the flags indicating which triggers are armed
 
262
            */ 
 
263
        if (vp2) {
 
264
            cmp = snmp_oid_compare(vp1->name, vp1->name_length,
 
265
                                   vp2->name, vp2->name_length);
 
266
            if ( cmp < 0 ) {
 
267
                /*
 
268
                 * If a new value has appeared, insert a matching
 
269
                 * dummy entry into the previous result list.
 
270
                 *
 
271
                 * XXX - check how this is best done.
 
272
                 */
 
273
                vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
274
                if (!vtmp) {
 
275
                    _mteTrigger_failure(
 
276
                          "failed to create mteTrigger temp varbind");
 
277
                    return;
 
278
                }
 
279
                vtmp->type = ASN_NULL;
 
280
                snmp_set_var_objid( vtmp, vp1->name, vp1->name_length );
 
281
                vtmp->next_variable = vp2;
 
282
                if (vp2_prev) {
 
283
                    vp2_prev->next_variable = vtmp;
 
284
                } else {
 
285
                    entry->old_results      = vtmp;
 
286
                }
 
287
                vp2_prev   = vtmp;
 
288
                vp1->index = MTE_ARMED_ALL;     /* XXX - plus a new flag */
 
289
                vp1_prev   = vp1;
 
290
                vp1        = vp1->next_variable;
 
291
            }
 
292
            else if ( cmp == 0 ) {
 
293
                /*
 
294
                 * If it's a continuing entry, just copy across the armed flags
 
295
                 */
 
296
                vp1->index = vp2->index;
 
297
                vp1_prev   = vp1;
 
298
                vp1        = vp1->next_variable;
 
299
                vp2_prev   = vp2;
 
300
                vp2        = vp2->next_variable;
 
301
            } else {
 
302
                /*
 
303
                 * If a value has just disappeared, insert a
 
304
                 * matching dummy entry into the current result list.
 
305
                 *
 
306
                 * XXX - check how this is best done.
 
307
                 *
 
308
                 */
 
309
                if ( vp2->type != ASN_NULL ) {
 
310
                    vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
311
                    if (!vtmp) {
 
312
                        _mteTrigger_failure(
 
313
                                 "failed to create mteTrigger temp varbind");
 
314
                        return;
 
315
                    }
 
316
                    vtmp->type = ASN_NULL;
 
317
                    snmp_set_var_objid( vtmp, vp2->name, vp2->name_length );
 
318
                    vtmp->next_variable = vp1;
 
319
                    if (vp1_prev) {
 
320
                        vp1_prev->next_variable = vtmp;
 
321
                    } else {
 
322
                        entry->old_results      = vtmp;
 
323
                    }
 
324
                    vp1_prev = vtmp;
 
325
                    vp2_prev = vp2;
 
326
                    vp2      = vp2->next_variable;
 
327
                } else {
 
328
                    /*
 
329
                     * But only if this entry has *just* disappeared.  If the
 
330
                     * entry from the last run was a dummy too, then remove it.
 
331
                     *   (leaving vp2_prev unchanged)
 
332
                     */
 
333
                    vtmp = vp2;
 
334
                    if (vp2_prev) {
 
335
                        vp2_prev->next_variable = vp2->next_variable;
 
336
                    } else {
 
337
                        entry->old_results      = vp2->next_variable;
 
338
                    }
 
339
                    vp2  = vp2->next_variable;
 
340
                    vtmp->next_variable = NULL;
 
341
                    snmp_free_varbind( vtmp );
 
342
                }
 
343
            }
 
344
        } else {
 
345
            /*
 
346
             * No more old results to compare.
 
347
             * Either all remaining values have only just been created ...
 
348
             *   (and we need to create dummy 'old' entries for them)
 
349
             */
 
350
            if ( vp2_prev ) {
 
351
                vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
352
                if (!vtmp) {
 
353
                    _mteTrigger_failure(
 
354
                             "failed to create mteTrigger temp varbind");
 
355
                    return;
 
356
                }
 
357
                vtmp->type = ASN_NULL;
 
358
                snmp_set_var_objid( vtmp, vp1->name, vp1->name_length );
 
359
                vtmp->next_variable     = vp2_prev->next_variable;
 
360
                vp2_prev->next_variable = vtmp;
 
361
                vp2_prev                = vtmp;
 
362
            }
 
363
            /*
 
364
             * ... or this is the first run through
 
365
             *   (and there were no old results at all)
 
366
             *
 
367
             * In either case, mark the current entry as armed and new.
 
368
             * Note that we no longer need to maintain 'vp1_prev'
 
369
             */
 
370
            vp1->index = MTE_ARMED_ALL; /* XXX - plus a new flag */
 
371
            vp1        = vp1->next_variable;
 
372
        }
 
373
    }
 
374
 
 
375
    /*
 
376
     * ... and then work through these result(s), deciding
 
377
     *     whether or not to trigger the corresponding event.
 
378
     *
 
379
     *  Note that there's no point in evaluating Existence or
 
380
     *    Boolean tests if there's no corresponding event.
 
381
     *   (Even if the trigger matched, nothing would be done anyway).
 
382
     */
 
383
    if ((entry->mteTriggerTest & MTE_TRIGGER_EXISTENCE) &&
 
384
        (entry->mteTExEvent[0] != '\0' )) {
 
385
        /*
 
386
         * If we don't have a record of previous results,
 
387
         * this must be the first time through, so consider
 
388
         * the mteTriggerExistenceStartup tests.
 
389
         */
 
390
        if ( !entry->old_results ) {
 
391
            /*
 
392
             * With the 'present(0)' test, the trigger should fire
 
393
             *   for each value in the varbind list returned
 
394
             *   (whether the monitored value is wildcarded or not).
 
395
             */
 
396
            if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_PRESENT) {
 
397
                for (vp1 = var; vp1; vp1=vp1->next_variable) {
 
398
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
399
                                 "Firing initial existence test: "));
 
400
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
401
                                 vp1->name, vp1->name_length));
 
402
                    DEBUGMSG((   "disman:event:trigger:fire",
 
403
                                 " (present)\n"));;
 
404
                    entry->mteTriggerXOwner   = entry->mteTExObjOwner;
 
405
                    entry->mteTriggerXObjects = entry->mteTExObjects;
 
406
                    entry->mteTriggerFired    = vp1;
 
407
                    n = entry->mteTriggerValueID_len;
 
408
                    mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, 
 
409
                                  entry, vp1->name+n, vp1->name_length-n);
 
410
                }
 
411
            }
 
412
            /*
 
413
             * An initial 'absent(1)' test only makes sense when
 
414
             *   monitoring a non-wildcarded OID (how would we know
 
415
             *   which rows of the table "ought" to exist, but don't?)
 
416
             */
 
417
            if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_ABSENT) {
 
418
                if (!(entry->flags & MTE_TRIGGER_FLAG_VWILD) &&
 
419
                    vp1->type == ASN_NULL ) {
 
420
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
421
                                 "Firing initial existence test: "));
 
422
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
423
                                 var->name, var->name_length));
 
424
                    DEBUGMSG((   "disman:event:trigger:fire",
 
425
                                 " (absent)\n"));;
 
426
                    entry->mteTriggerXOwner   = entry->mteTExObjOwner;
 
427
                    entry->mteTriggerXObjects = entry->mteTExObjects;
 
428
                    /*
 
429
                     * It's unclear what value the 'mteHotValue' payload
 
430
                     *  should take when a monitored instance does not
 
431
                     *  exist on startup. The only sensible option is
 
432
                     *  to report a NULL value, but this clashes with
 
433
                     * the syntax of the mteHotValue MIB object.
 
434
                     */
 
435
                    entry->mteTriggerFired    = vp1;
 
436
                    n = entry->mteTriggerValueID_len;
 
437
                    mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, 
 
438
                                  entry, vp1->name+n, vp1->name_length-n);
 
439
                }
 
440
            }
 
441
        } /* !old_results */
 
442
            /*
 
443
             * Otherwise, compare the current set of results with
 
444
             * the previous ones, looking for changes.  We can
 
445
             * assume that the two lists match (see above).
 
446
             */
 
447
        else {
 
448
            for (vp1 = var, vp2 = entry->old_results;
 
449
                 vp1;
 
450
                 vp1=vp1->next_variable, vp2=vp2->next_variable) {
 
451
 
 
452
                /* Use this field to indicate that the trigger should fire */
 
453
                entry->mteTriggerFired = NULL;
 
454
                reason                 = NULL;
 
455
 
 
456
                if ((entry->mteTExTest & MTE_EXIST_PRESENT) &&
 
457
                    (vp1->type != ASN_NULL) &&
 
458
                    (vp2->type == ASN_NULL)) {
 
459
                    /* A new instance has appeared */
 
460
                    entry->mteTriggerFired = vp1;
 
461
                    reason = "(present)";
 
462
 
 
463
                } else if ((entry->mteTExTest & MTE_EXIST_ABSENT) &&
 
464
                    (vp1->type == ASN_NULL) &&
 
465
                    (vp2->type != ASN_NULL)) {
 
466
 
 
467
                    /*
 
468
                     * A previous instance has disappeared.
 
469
                     *
 
470
                     * It's unclear what value the 'mteHotValue' payload
 
471
                     *  should take when this happens - the previous
 
472
                     *  value (vp2), or a NULL value (vp1) ?
 
473
                     * NULL makes more sense logically, but clashes
 
474
                     *  with the syntax of the mteHotValue MIB object.
 
475
                     */
 
476
                    entry->mteTriggerFired = vp2;
 
477
                    reason = "(absent)";
 
478
 
 
479
                } else if ((entry->mteTExTest & MTE_EXIST_CHANGED) &&
 
480
                    ((vp1->val_len != vp2->val_len) || 
 
481
                     (memcmp( vp1->val.string, vp2->val.string,
 
482
                              vp1->val_len) != 0 ))) {
 
483
                    /*
 
484
                     * This comparison detects changes in *any* type
 
485
                     *  of value, numeric or string (or even OID).
 
486
                     *
 
487
                     * Unfortunately, the default 'mteTriggerFired'
 
488
                     *  notification payload can't report non-numeric
 
489
                     *  changes properly (see syntax of 'mteHotValue')
 
490
                     */
 
491
                    entry->mteTriggerFired = vp1;
 
492
                    reason = "(changed)";
 
493
                }
 
494
                if ( entry->mteTriggerFired ) {
 
495
                    /*
 
496
                     * One of the above tests has matched,
 
497
                     *   so fire the trigger.
 
498
                     */
 
499
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
500
                                 "Firing existence test: "));
 
501
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
502
                                 vp1->name, vp1->name_length));
 
503
                    DEBUGMSG((   "disman:event:trigger:fire",
 
504
                                 " %s\n", reason));;
 
505
                    entry->mteTriggerXOwner   = entry->mteTExObjOwner;
 
506
                    entry->mteTriggerXObjects = entry->mteTExObjects;
 
507
                    n = entry->mteTriggerValueID_len;
 
508
                    mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent, 
 
509
                                  entry, vp1->name+n, vp1->name_length-n);
 
510
                }
 
511
            }
 
512
        } /* !old_results - end of else block */
 
513
    } /* MTE_TRIGGER_EXISTENCE */
 
514
 
 
515
 
 
516
    if (( entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN   ) ||
 
517
        ( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD )) {
 
518
        /*
 
519
         * Although Existence tests can work with any syntax values,
 
520
         * Boolean and Threshold tests are integer-only.  Ensure that
 
521
         * the returned value(s) are appropriate.
 
522
         *
 
523
         * Note that we only need to check the first value, since all
 
524
         *  instances of a given object should have the same syntax.
 
525
         */
 
526
        switch (var->type) {
 
527
        case ASN_INTEGER:
 
528
        case ASN_COUNTER:
 
529
        case ASN_GAUGE:
 
530
        case ASN_TIMETICKS:
 
531
        case ASN_UINTEGER:
 
532
        case ASN_COUNTER64:
 
533
#ifdef OPAQUE_SPECIAL_TYPES
 
534
        case ASN_OPAQUE_COUNTER64:
 
535
        case ASN_OPAQUE_U64:
 
536
        case ASN_OPAQUE_I64:
 
537
#endif
 
538
            /* OK */
 
539
            break;
 
540
        default:
 
541
            /*
 
542
             * Other syntax values can't be used for Boolean/Theshold
 
543
             * tests. Report this as an error, and then rotate the
 
544
             * results ready for the next run, (which will presumably
 
545
             * also detect this as an error once again!)
 
546
             */
 
547
            DEBUGMSGTL(( "disman:event:trigger:fire",
 
548
                         "Returned non-integer result(s): "));
 
549
            DEBUGMSGOID(("disman:event:trigger:fire",
 
550
                         var->name, var->name_length));
 
551
            DEBUGMSG((   "disman:event:trigger:fire",
 
552
                         " (boolean/threshold) %d\n", var->type));;
 
553
            snmp_free_varbind( entry->old_results );
 
554
            entry->old_results = var;
 
555
            return;
 
556
        }
 
557
 
 
558
 
 
559
        /*
 
560
         * Retrieve the discontinuity markers for delta-valued samples.
 
561
         * (including sysUpTime.0 if not specified explicitly).
 
562
         */
 
563
        if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) {
 
564
            /*
 
565
             * We'll need sysUpTime.0 regardless...
 
566
             */
 
567
            DEBUGMSGTL(("disman:event:delta", "retrieve sysUpTime.0\n"));
 
568
            memset( &sysUT_var, 0, sizeof( netsnmp_variable_list ));
 
569
            snmp_set_var_objid( &sysUT_var, _sysUpTime_instance,
 
570
                                            _sysUpTime_inst_len );
 
571
            netsnmp_query_get(  &sysUT_var, entry->session );
 
572
 
 
573
            if (!(entry->flags & MTE_TRIGGER_FLAG_SYSUPT)) {
 
574
                /*
 
575
                 * ... but only retrieve the configured discontinuity
 
576
                 *      marker(s) if they refer to something different.
 
577
                 */
 
578
                DEBUGMSGTL(( "disman:event:delta",
 
579
                             "retrieve discontinuity marker(s): "));
 
580
                DEBUGMSGOID(("disman:event:delta", entry->mteDeltaDiscontID,
 
581
                                               entry->mteDeltaDiscontID_len ));
 
582
                DEBUGMSG((   "disman:event:delta", " %s\n", 
 
583
                     (entry->flags & MTE_TRIGGER_FLAG_DWILD ? " (wild)" : "")));
 
584
 
 
585
                dvar = (netsnmp_variable_list *)
 
586
                                SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
587
                if (!dvar) {
 
588
                    _mteTrigger_failure(
 
589
                            "failed to create mteTrigger delta query varbind");
 
590
                    return;
 
591
                }
 
592
                snmp_set_var_objid( dvar, entry->mteDeltaDiscontID,
 
593
                                          entry->mteDeltaDiscontID_len );
 
594
                if ( entry->flags & MTE_TRIGGER_FLAG_DWILD ) {
 
595
                    netsnmp_query_walk( dvar, entry->session );
 
596
                } else {
 
597
                    netsnmp_query_get(  dvar, entry->session );
 
598
                }
 
599
                if ( n != SNMP_ERR_NOERROR ) {
 
600
                    _mteTrigger_failure( "failed to run mteTrigger delta query" );
 
601
                    snmp_free_varbind( dvar );
 
602
                    return;
 
603
                }
 
604
            }
 
605
 
 
606
            /*
 
607
             * We can't calculate delta values the first time through,
 
608
             *  so there's no point in evaluating the remaining tests.
 
609
             *
 
610
             * Save the results (and discontinuity markers),
 
611
             *   ready for the next run.
 
612
             */
 
613
            if ( !entry->old_results ) {
 
614
                entry->old_results =  var;
 
615
                entry->old_deltaDs = dvar;
 
616
                entry->sysUpTime   = *sysUT_var.val.integer;
 
617
                return;
 
618
            }
 
619
            /*
 
620
             * If the sysUpTime marker has been reset (or strictly,
 
621
             *   has advanced by less than the monitor frequency),
 
622
             *  there's no point in trying the remaining tests.
 
623
             */
 
624
 
 
625
            if (*sysUT_var.val.integer < entry->sysUpTime) {
 
626
                DEBUGMSGTL(( "disman:event:delta",
 
627
                             "single discontinuity: (sysUT)\n"));
 
628
                snmp_free_varbind( entry->old_results );
 
629
                snmp_free_varbind( entry->old_deltaDs );
 
630
                entry->old_results =  var;
 
631
                entry->old_deltaDs = dvar;
 
632
                entry->sysUpTime   = *sysUT_var.val.integer;
 
633
                return;
 
634
            }
 
635
            /*
 
636
             * Similarly if a separate (non-wildcarded) discontinuity
 
637
             *  marker has changed, then there's no
 
638
             *  point in trying to evaluate these tests either.
 
639
             */
 
640
            if (!(entry->flags & MTE_TRIGGER_FLAG_DWILD)  &&
 
641
                !(entry->flags & MTE_TRIGGER_FLAG_SYSUPT) &&
 
642
                  (!entry->old_deltaDs ||
 
643
                   (entry->old_deltaDs->val.integer != dvar->val.integer))) {
 
644
                DEBUGMSGTL((  "disman:event:delta", "single discontinuity: ("));
 
645
                DEBUGMSGOID(( "disman:event:delta", entry->mteDeltaDiscontID,
 
646
                                           entry->mteDeltaDiscontID_len));
 
647
                DEBUGMSG((    "disman:event:delta", ")\n"));
 
648
                snmp_free_varbind( entry->old_results );
 
649
                snmp_free_varbind( entry->old_deltaDs );
 
650
                entry->old_results =  var;
 
651
                entry->old_deltaDs = dvar;
 
652
                entry->sysUpTime   = *sysUT_var.val.integer;
 
653
                return;
 
654
            }
 
655
 
 
656
            /*
 
657
             * Ensure that the list of (wildcarded) discontinuity 
 
658
             *  markers matches the list of monitored values
 
659
             *  (inserting/removing discontinuity varbinds as needed)
 
660
             *
 
661
             * XXX - An alternative approach would be to use the list
 
662
             *    of monitored values (instance subidentifiers) to build
 
663
             *    the exact list of delta markers to retrieve earlier.
 
664
             */
 
665
            if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
 
666
                vp1      =  var;
 
667
                vp2      = dvar;
 
668
                vp2_prev = NULL;
 
669
                n  = entry->mteTriggerValueID_len;
 
670
                n2 = entry->mteDeltaDiscontID_len;
 
671
                while (vp1) {
 
672
                    /*
 
673
                     * For each monitored instance, check whether
 
674
                     *   there's a matching discontinuity entry.
 
675
                     */
 
676
                    cmp = snmp_oid_compare(vp1->name+n,  vp1->name_length-n,
 
677
                                           vp2->name+n2, vp2->name_length-n2 );
 
678
                    if ( cmp < 0 ) {
 
679
                        /*
 
680
                         * If a discontinuity entry is missing,
 
681
                         *   insert a (dummy) varbind.
 
682
                         * The corresponding delta calculation will
 
683
                         *   fail, but this simplifies the later code.
 
684
                         */
 
685
                        vtmp = (netsnmp_variable_list *)
 
686
                                SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
 
687
                        if (!vtmp) {
 
688
                            _mteTrigger_failure(
 
689
                                  "failed to create mteTrigger discontinuity varbind");
 
690
                            return;
 
691
                        }
 
692
                        snmp_set_var_objid(vtmp, entry->mteDeltaDiscontID,
 
693
                                                 entry->mteDeltaDiscontID_len);
 
694
                            /* XXX - append instance subids */
 
695
                        vtmp->next_variable     = vp2;
 
696
                        vp2_prev->next_variable = vtmp;
 
697
                        vp2_prev                = vtmp;
 
698
                        vp1 = vp1->next_variable;
 
699
                    } else if ( cmp == 0 ) {
 
700
                        /*
 
701
                         * Matching discontinuity entry -  all OK.
 
702
                         */
 
703
                        vp2_prev = vp2;
 
704
                        vp2      = vp2->next_variable;
 
705
                        vp1      = vp1->next_variable;
 
706
                    } else {
 
707
                        /*
 
708
                         * Remove unneeded discontinuity entry
 
709
                         */
 
710
                        vtmp = vp2;
 
711
                        vp2_prev->next_variable = vp2->next_variable;
 
712
                        vp2                     = vp2->next_variable;
 
713
                        vtmp->next_variable = NULL;
 
714
                        snmp_free_varbind( vtmp );
 
715
                    }
 
716
                }
 
717
                /*
 
718
                 * XXX - Now need to ensure that the old list of
 
719
                 *   delta discontinuity markers matches as well.
 
720
                 */
 
721
            }
 
722
        } /* delta samples */
 
723
    } /* Boolean/Threshold test checks */
 
724
 
 
725
 
 
726
 
 
727
    /*
 
728
     * Only run the Boolean tests if there's an event to be triggered
 
729
     */
 
730
    if ((entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN) &&
 
731
        (entry->mteTBoolEvent[0] != '\0' )) {
 
732
 
 
733
        if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
 
734
            vp2 = entry->old_results;
 
735
            if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
 
736
                dv1 = dvar;
 
737
                dv2 = entry->old_deltaDs;
 
738
            }
 
739
        }
 
740
        for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
 
741
            /*
 
742
             * Determine the value to be monitored...
 
743
             */
 
744
            if ( !vp1->val.integer ) {  /* No value */
 
745
                if ( vp2 )
 
746
                    vp2 = vp2->next_variable;
 
747
                continue;
 
748
            }
 
749
            if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
 
750
                if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
 
751
                    /*
 
752
                     * We've already checked any non-wildcarded
 
753
                     *   discontinuity markers (inc. sysUpTime.0).
 
754
                     * Validate this particular sample against
 
755
                     *   the relevant wildcarded marker...
 
756
                     */
 
757
                    if ((dv1->type == ASN_NULL)  ||
 
758
                        (dv1->type != dv2->type) ||
 
759
                        (*dv1->val.integer != *dv2->val.integer)) {
 
760
                        /*
 
761
                         * Bogus or changed discontinuity marker.
 
762
                         * Need to skip this sample.
 
763
                         */
 
764
    DEBUGMSGTL(( "disman:event:delta", "discontinuity occurred: "));
 
765
    DEBUGMSGOID(("disman:event:delta", vp1->name,
 
766
                                       vp1->name_length ));
 
767
    DEBUGMSG((   "disman:event:delta", " \n" ));
 
768
                        vp2 = vp2->next_variable;
 
769
                        continue;
 
770
                    }
 
771
                }
 
772
                /*
 
773
                 * ... and check there is a previous sample to calculate
 
774
                 *   the delta value against (regardless of whether the
 
775
                 *   discontinuity marker was wildcarded or not).
 
776
                 */
 
777
                if (vp2->type == ASN_NULL) {
 
778
    DEBUGMSGTL(( "disman:event:delta", "missing sample: "));
 
779
    DEBUGMSGOID(("disman:event:delta", vp1->name,
 
780
                                       vp1->name_length ));
 
781
    DEBUGMSG((   "disman:event:delta", " \n" ));
 
782
                    vp2 = vp2->next_variable;
 
783
                    continue;
 
784
                }
 
785
                value = (*vp1->val.integer - *vp2->val.integer);
 
786
    DEBUGMSGTL(( "disman:event:delta", "delta sample: "));
 
787
    DEBUGMSGOID(("disman:event:delta", vp1->name,
 
788
                                       vp1->name_length ));
 
789
    DEBUGMSG((   "disman:event:delta", " (%d - %d) = %d\n",
 
790
                *vp1->val.integer,  *vp2->val.integer, value));
 
791
                vp2 = vp2->next_variable;
 
792
            } else {
 
793
                value = *vp1->val.integer;
 
794
            }
 
795
 
 
796
            /*
 
797
             * ... evaluate the comparison ...
 
798
             */
 
799
            switch (entry->mteTBoolComparison) {
 
800
            case MTE_BOOL_UNEQUAL:
 
801
                cmp = ( value != entry->mteTBoolValue );
 
802
                break;
 
803
            case MTE_BOOL_EQUAL:
 
804
                cmp = ( value == entry->mteTBoolValue );
 
805
                break;
 
806
            case MTE_BOOL_LESS:
 
807
                cmp = ( value <  entry->mteTBoolValue );
 
808
                break;
 
809
            case MTE_BOOL_LESSEQUAL:
 
810
                cmp = ( value <= entry->mteTBoolValue );
 
811
                break;
 
812
            case MTE_BOOL_GREATER:
 
813
                cmp = ( value >  entry->mteTBoolValue );
 
814
                break;
 
815
            case MTE_BOOL_GREATEREQUAL:
 
816
                cmp = ( value >= entry->mteTBoolValue );
 
817
                break;
 
818
            }
 
819
    DEBUGMSGTL(( "disman:event:delta", "Bool comparison: (%d %s %d) %d\n",
 
820
                          value, _ops[entry->mteTBoolComparison],
 
821
                          entry->mteTBoolValue, cmp));
 
822
 
 
823
            /*
 
824
             * ... and decide whether to trigger the event.
 
825
             *    (using the 'index' field of the varbind structure
 
826
             *     to remember whether the trigger has already fired)
 
827
             */
 
828
            if ( cmp ) {
 
829
                if ((entry->old_results ||
 
830
                     (entry->flags & MTE_TRIGGER_FLAG_BSTART)) &&
 
831
                    (vp1->index & MTE_ARMED_BOOLEAN )) {
 
832
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
833
                                 "Firing boolean test: "));
 
834
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
835
                                 vp1->name, vp1->name_length));
 
836
                    DEBUGMSG((   "disman:event:trigger:fire", "%s\n",
 
837
                                  (entry->old_results ? "" : " (startup)")));
 
838
                    vp1->index &= ~MTE_ARMED_BOOLEAN;
 
839
                    entry->mteTriggerXOwner   = entry->mteTBoolObjOwner;
 
840
                    entry->mteTriggerXObjects = entry->mteTBoolObjects;
 
841
                    /*
 
842
                     * XXX - when firing a delta-based trigger, should
 
843
                     *   'mteHotValue' report the actual value sampled
 
844
                     *   (as here), or the delta that triggered the event ?
 
845
                     */
 
846
                    entry->mteTriggerFired    = vp1;
 
847
                    n = entry->mteTriggerValueID_len;
 
848
                    mteEvent_fire(entry->mteTBoolEvOwner, entry->mteTBoolEvent, 
 
849
                                  entry, vp1->name+n, vp1->name_length-n);
 
850
                }
 
851
            } else {
 
852
                vp1->index |= MTE_ARMED_BOOLEAN;
 
853
            }
 
854
        }
 
855
    }
 
856
 
 
857
 
 
858
    /*
 
859
     * Only run the basic threshold tests if there's an event to
 
860
     *    be triggered.  (Either rising or falling will do)
 
861
     */
 
862
    if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) &&
 
863
        ((entry->mteTThRiseEvent[0] != '\0' ) ||
 
864
         (entry->mteTThFallEvent[0] != '\0' ))) {
 
865
 
 
866
        /*
 
867
         * The same delta-sample validation from Boolean
 
868
         *   tests also applies here too.
 
869
         */
 
870
        if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
 
871
            vp2 = entry->old_results;
 
872
            if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
 
873
                dv1 = dvar;
 
874
                dv2 = entry->old_deltaDs;
 
875
            }
 
876
        }
 
877
        for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
 
878
            /*
 
879
             * Determine the value to be monitored...
 
880
             */
 
881
            if ( !vp1->val.integer ) {  /* No value */
 
882
                if ( vp2 )
 
883
                    vp2 = vp2->next_variable;
 
884
                continue;
 
885
            }
 
886
            if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
 
887
                if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
 
888
                    /*
 
889
                     * We've already checked any non-wildcarded
 
890
                     *   discontinuity markers (inc. sysUpTime.0).
 
891
                     * Validate this particular sample against
 
892
                     *   the relevant wildcarded marker...
 
893
                     */
 
894
                    if ((dv1->type == ASN_NULL)  ||
 
895
                        (dv1->type != dv2->type) ||
 
896
                        (*dv1->val.integer != *dv2->val.integer)) {
 
897
                        /*
 
898
                         * Bogus or changed discontinuity marker.
 
899
                         * Need to skip this sample.
 
900
                         */
 
901
                        vp2 = vp2->next_variable;
 
902
                        continue;
 
903
                    }
 
904
                }
 
905
                /*
 
906
                 * ... and check there is a previous sample to calculate
 
907
                 *   the delta value against (regardless of whether the
 
908
                 *   discontinuity marker was wildcarded or not).
 
909
                 */
 
910
                if (vp2->type == ASN_NULL) {
 
911
                    vp2 = vp2->next_variable;
 
912
                    continue;
 
913
                }
 
914
                value = (*vp1->val.integer - *vp2->val.integer);
 
915
                vp2 = vp2->next_variable;
 
916
            } else {
 
917
                value = *vp1->val.integer;
 
918
            }
 
919
 
 
920
            /*
 
921
             * ... evaluate the single-value comparisons,
 
922
             *     and decide whether to trigger the event.
 
923
             */
 
924
            cmp = vp1->index;   /* working copy of 'armed' flags */
 
925
            if ( value >= entry->mteTThRiseValue ) {
 
926
                if ((entry->old_results ||
 
927
                     (entry->mteTThStartup & MTE_THRESH_START_RISE)) &&
 
928
                    (vp1->index & MTE_ARMED_TH_RISE )) {
 
929
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
930
                                 "Firing rising threshold test: "));
 
931
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
932
                                 vp1->name, vp1->name_length));
 
933
                    DEBUGMSG((   "disman:event:trigger:fire", "%s\n",
 
934
                                 (entry->old_results ? "" : " (startup)")));
 
935
                    cmp &= ~MTE_ARMED_TH_RISE;
 
936
                    cmp |=  MTE_ARMED_TH_FALL;
 
937
                    /*
 
938
                     * If no riseEvent is configured, we need still to
 
939
                     *  set the armed flags appropriately, but there's
 
940
                     *  no point in trying to fire the (missing) event.
 
941
                     */
 
942
                    if (entry->mteTThRiseEvent[0] != '\0' ) {
 
943
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
 
944
                        entry->mteTriggerXObjects = entry->mteTThObjects;
 
945
                        entry->mteTriggerFired    = vp1;
 
946
                        n = entry->mteTriggerValueID_len;
 
947
                        mteEvent_fire(entry->mteTThRiseOwner,
 
948
                                      entry->mteTThRiseEvent, 
 
949
                                      entry, vp1->name+n, vp1->name_length-n);
 
950
                    }
 
951
                }
 
952
            }
 
953
 
 
954
            if ( value <= entry->mteTThFallValue ) {
 
955
                if ((entry->old_results ||
 
956
                     (entry->mteTThStartup & MTE_THRESH_START_FALL)) &&
 
957
                    (vp1->index & MTE_ARMED_TH_FALL )) {
 
958
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
959
                                 "Firing falling threshold test: "));
 
960
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
961
                                 vp1->name, vp1->name_length));
 
962
                    DEBUGMSG((   "disman:event:trigger:fire", "%s\n",
 
963
                                 (entry->old_results ? "" : " (startup)")));
 
964
                    cmp &= ~MTE_ARMED_TH_FALL;
 
965
                    cmp |=  MTE_ARMED_TH_RISE;
 
966
                    /*
 
967
                     * Similarly, if no fallEvent is configured,
 
968
                     *  there's no point in trying to fire it either.
 
969
                     */
 
970
                    if (entry->mteTThRiseEvent[0] != '\0' ) {
 
971
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
 
972
                        entry->mteTriggerXObjects = entry->mteTThObjects;
 
973
                        entry->mteTriggerFired    = vp1;
 
974
                        n = entry->mteTriggerValueID_len;
 
975
                        mteEvent_fire(entry->mteTThFallOwner,
 
976
                                      entry->mteTThFallEvent, 
 
977
                                      entry, vp1->name+n, vp1->name_length-n);
 
978
                    }
 
979
                }
 
980
            }
 
981
            vp1->index = cmp;
 
982
        }
 
983
    }
 
984
 
 
985
    /*
 
986
     * The same processing also works for delta-threshold tests (if configured)
 
987
     */
 
988
    if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) &&
 
989
        ((entry->mteTThDRiseEvent[0] != '\0' ) ||
 
990
         (entry->mteTThDFallEvent[0] != '\0' ))) {
 
991
 
 
992
        /*
 
993
         * Delta-threshold tests can only be used with
 
994
         *   absolute valued samples.
 
995
         */
 
996
        vp2 = entry->old_results;
 
997
        if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
 
998
            DEBUGMSGTL(( "disman:event:trigger",
 
999
                         "Delta-threshold on delta-sample\n"));
 
1000
        } else if ( vp2 != NULL ) {
 
1001
          for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
 
1002
            /*
 
1003
             * Determine the value to be monitored...
 
1004
             *  (similar to previous delta-sample processing,
 
1005
             *   but without the discontinuity marker checks)
 
1006
             */
 
1007
            if (!vp2) {
 
1008
                break;   /* Run out of 'old' values */
 
1009
            }
 
1010
            if (( !vp1->val.integer ) ||
 
1011
                (vp2->type == ASN_NULL)) {
 
1012
                vp2 = vp2->next_variable;
 
1013
                continue;
 
1014
            }
 
1015
            value = (*vp1->val.integer - *vp2->val.integer);
 
1016
            vp2 = vp2->next_variable;
 
1017
 
 
1018
            /*
 
1019
             * ... evaluate the single-value comparisons,
 
1020
             *     and decide whether to trigger the event.
 
1021
             */
 
1022
            cmp = vp1->index;   /* working copy of 'armed' flags */
 
1023
            if ( value >= entry->mteTThDRiseValue ) {
 
1024
                if (vp1->index & MTE_ARMED_TH_DRISE ) {
 
1025
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
1026
                                 "Firing rising delta threshold test: "));
 
1027
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
1028
                                 vp1->name, vp1->name_length));
 
1029
                    DEBUGMSG((   "disman:event:trigger:fire", "\n"));
 
1030
                    cmp &= ~MTE_ARMED_TH_DRISE;
 
1031
                    cmp |=  MTE_ARMED_TH_DFALL;
 
1032
                    /*
 
1033
                     * If no riseEvent is configured, we need still to
 
1034
                     *  set the armed flags appropriately, but there's
 
1035
                     *  no point in trying to fire the (missing) event.
 
1036
                     */
 
1037
                    if (entry->mteTThDRiseEvent[0] != '\0' ) {
 
1038
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
 
1039
                        entry->mteTriggerXObjects = entry->mteTThObjects;
 
1040
                        entry->mteTriggerFired    = vp1;
 
1041
                        n = entry->mteTriggerValueID_len;
 
1042
                        mteEvent_fire(entry->mteTThDRiseOwner,
 
1043
                                      entry->mteTThDRiseEvent, 
 
1044
                                      entry, vp1->name+n, vp1->name_length-n);
 
1045
                    }
 
1046
                }
 
1047
            }
 
1048
 
 
1049
            if ( value <= entry->mteTThDFallValue ) {
 
1050
                if (vp1->index & MTE_ARMED_TH_DFALL ) {
 
1051
                    DEBUGMSGTL(( "disman:event:trigger:fire",
 
1052
                                 "Firing falling delta threshold test: "));
 
1053
                    DEBUGMSGOID(("disman:event:trigger:fire",
 
1054
                                 vp1->name, vp1->name_length));
 
1055
                    DEBUGMSG((   "disman:event:trigger:fire", "\n"));
 
1056
                    cmp &= ~MTE_ARMED_TH_DFALL;
 
1057
                    cmp |=  MTE_ARMED_TH_DRISE;
 
1058
                    /*
 
1059
                     * Similarly, if no fallEvent is configured,
 
1060
                     *  there's no point in trying to fire it either.
 
1061
                     */
 
1062
                    if (entry->mteTThDRiseEvent[0] != '\0' ) {
 
1063
                        entry->mteTriggerXOwner   = entry->mteTThObjOwner;
 
1064
                        entry->mteTriggerXObjects = entry->mteTThObjects;
 
1065
                        entry->mteTriggerFired    = vp1;
 
1066
                        n = entry->mteTriggerValueID_len;
 
1067
                        mteEvent_fire(entry->mteTThDFallOwner,
 
1068
                                      entry->mteTThDFallEvent, 
 
1069
                                      entry, vp1->name+n, vp1->name_length-n);
 
1070
                    }
 
1071
                }
 
1072
            }
 
1073
            vp1->index = cmp;
 
1074
          }
 
1075
        }
 
1076
    }
 
1077
 
 
1078
    /*
 
1079
     * Finally, rotate the results - ready for the next run.
 
1080
     */
 
1081
    snmp_free_varbind( entry->old_results );
 
1082
    entry->old_results = var;
 
1083
    if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) {
 
1084
        snmp_free_varbind( entry->old_deltaDs );
 
1085
        entry->old_deltaDs = dvar;
 
1086
        entry->sysUpTime   = *sysUT_var.val.integer;
 
1087
    }
 
1088
}
 
1089
 
 
1090
void
 
1091
mteTrigger_enable( struct mteTrigger *entry )
 
1092
{
 
1093
    if (!entry)
 
1094
        return;
 
1095
 
 
1096
    if (entry->alarm) {
 
1097
        /* XXX - or explicitly call mteTrigger_disable ?? */
 
1098
        snmp_alarm_unregister( entry->alarm );
 
1099
        entry->alarm = 0;
 
1100
    }
 
1101
 
 
1102
    if (entry->mteTriggerFrequency) {
 
1103
        /*
 
1104
         * register once to run ASAP, and another to run
 
1105
         * at the trigger frequency
 
1106
         */
 
1107
        snmp_alarm_register(0, 0, mteTrigger_run, entry );
 
1108
        entry->alarm = snmp_alarm_register(
 
1109
                           entry->mteTriggerFrequency, SA_REPEAT,
 
1110
                           mteTrigger_run, entry );
 
1111
    }
 
1112
}
 
1113
 
 
1114
void
 
1115
mteTrigger_disable( struct mteTrigger *entry )
 
1116
{
 
1117
    if (!entry)
 
1118
        return;
 
1119
 
 
1120
    if (entry->alarm) {
 
1121
        snmp_alarm_unregister( entry->alarm );
 
1122
        entry->alarm = 0;
 
1123
        /* XXX - perhaps release any previous results */
 
1124
    }
 
1125
}
 
1126
 
 
1127
long _mteTrigger_MaxCount = 0;
 
1128
long _mteTrigger_countEntries(void)
 
1129
{
 
1130
    struct mteTrigger *entry;
 
1131
    netsnmp_tdata_row *row;
 
1132
    long count = 0;
 
1133
 
 
1134
    for (row = netsnmp_tdata_row_first(trigger_table_data);
 
1135
         row;
 
1136
         row = netsnmp_tdata_row_next(trigger_table_data, row)) {
 
1137
        entry  = (struct mteTrigger *)row->data;
 
1138
        count += entry->count;
 
1139
    }
 
1140
 
 
1141
    return count;
 
1142
}
 
1143
 
 
1144
long mteTrigger_getNumEntries(int max)
 
1145
{
 
1146
    long count;
 
1147
    /* XXX - implement some form of caching ??? */
 
1148
    count = _mteTrigger_countEntries();
 
1149
    if ( count > _mteTrigger_MaxCount )
 
1150
        _mteTrigger_MaxCount = count;
 
1151
    
 
1152
    return ( max ?  _mteTrigger_MaxCount : count);
 
1153
}