added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / Rmon / history.c
1 /**************************************************************
2  * Copyright (C) 2001 Alex Rozin, Optical Access 
3  *
4  *                     All Rights Reserved
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation for any purpose and without fee is hereby granted,
8  * provided that the above copyright notice appear in all copies and that
9  * both that copyright notice and this permission notice appear in
10  * supporting documentation.
11  * 
12  * ALEX ROZIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
13  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
14  * ALEX ROZIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
15  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
16  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
17  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
18  * SOFTWARE.
19  ******************************************************************/
20
21 #include <stdlib.h>
22 #include <sys/time.h>
23 #include <unistd.h>
24
25 #include <net-snmp/net-snmp-config.h>
26 #include <net-snmp/net-snmp-includes.h>
27 #include <net-snmp/agent/net-snmp-agent-includes.h>
28
29 #include "util_funcs.h"
30
31 #include "history.h"
32
33 /*
34  * Implementation headers 
35  */
36 #include "agutil_api.h"
37 #include "row_api.h"
38
39 /*
40  * File scope definitions section 
41  */
42
43 #define historyControlEntryFirstIndexBegin      11
44
45 #define CTRL_INDEX              3
46 #define CTRL_DATASOURCE         4
47 #define CTRL_BUCKETSREQUESTED   5
48 #define CTRL_BUCKETSGRANTED     6
49 #define CTRL_INTERVAL           7
50 #define CTRL_OWNER              8
51 #define CTRL_STATUS             9
52
53 #define DATA_INDEX              3
54 #define DATA_SAMPLEINDEX        4
55 #define DATA_INTERVALSTART      5
56 #define DATA_DROPEVENTS         6
57 #define DATA_OCTETS             7
58 #define DATA_PKTS               8
59 #define DATA_BROADCASTPKTS      9
60 #define DATA_MULTICASTPKTS      10
61 #define DATA_CRCALIGNERRORS     11
62 #define DATA_UNDERSIZEPKTS      12
63 #define DATA_OVERSIZEPKTS       13
64 #define DATA_FRAGMENTS          14
65 #define DATA_JABBERS            15
66 #define DATA_COLLISIONS         16
67 #define DATA_UTILIZATION        17
68
69 /*
70  * defaults & limitations 
71  */
72
73 #define MAX_BUCKETS_IN_CRTL_ENTRY       50
74 #define HIST_DEF_BUCK_REQ               50
75 #define HIST_DEF_INTERVAL               1800
76 static VAR_OID_T DEFAULT_DATA_SOURCE = { 11,    /* ifIndex.1 */
77     {1, 3, 6, 1, 2, 1, 2, 2, 1, 1, 1}
78 };
79
80 typedef struct data_struct_t {
81     struct data_struct_t *next;
82     u_long          data_index;
83     u_long          start_interval;
84     u_long          utilization;
85     ETH_STATS_T     EthData;
86 } DATA_ENTRY_T;
87
88 typedef struct {
89     u_long          interval;
90     u_long          timer_id;
91     VAR_OID_T       data_source;
92
93     u_long          coeff;
94     DATA_ENTRY_T    previous_bucket;
95     SCROLLER_T      scrlr;
96
97 } CRTL_ENTRY_T;
98
99 static TABLE_DEFINTION_T HistoryCtrlTable;
100 static TABLE_DEFINTION_T *table_ptr = &HistoryCtrlTable;
101
102 /*
103  * Main section 
104  */
105
106 #  define Leaf_historyControlDataSource                    2
107 #  define Leaf_historyControlBucketsRequested              3
108 #  define Leaf_historyControlInterval                      5
109 #  define Leaf_historyControlOwner                         6
110 #  define Leaf_historyControlStatus                        7
111 #  define MIN_historyControlBucketsRequested               1
112 #  define MAX_historyControlBucketsRequested               65535
113 #  define MIN_historyControlInterval                       1
114 #  define MAX_historyControlInterval                       3600
115
116 static int
117 write_historyControl(int action, u_char * var_val, u_char var_val_type,
118                      size_t var_val_len, u_char * statP,
119                      oid * name, size_t name_len)
120 {
121     long            long_temp;
122     int             leaf_id, snmp_status;
123     static int      prev_action = COMMIT;
124     RMON_ENTRY_T   *hdr;
125     CRTL_ENTRY_T   *cloned_body;
126     CRTL_ENTRY_T   *body;
127
128     switch (action) {
129     case RESERVE1:
130     case FREE:
131     case UNDO:
132     case ACTION:
133     case COMMIT:
134     default:
135         return ROWAPI_do_another_action(name,
136                                         historyControlEntryFirstIndexBegin,
137                                         action, &prev_action, table_ptr,
138                                         sizeof(CRTL_ENTRY_T));
139     case RESERVE2:
140         /*
141          * get values from PDU, check them and save them in the cloned entry 
142          */
143         long_temp = name[historyControlEntryFirstIndexBegin];
144         leaf_id = (int) name[historyControlEntryFirstIndexBegin - 1];
145         hdr = ROWAPI_find(table_ptr, long_temp);        /* it MUST be OK */
146         cloned_body = (CRTL_ENTRY_T *) hdr->tmp;
147         body = (CRTL_ENTRY_T *) hdr->body;
148         switch (leaf_id) {
149         case Leaf_historyControlDataSource:
150             snmp_status = AGUTIL_get_oid_value(var_val, var_val_type,
151                                                var_val_len,
152                                                &cloned_body->data_source);
153             if (SNMP_ERR_NOERROR != snmp_status) {
154                 ag_trace("can't browse historyControlDataSource");
155                 return snmp_status;
156             }
157             if (RMON1_ENTRY_UNDER_CREATION != hdr->status &&
158                 snmp_oid_compare(cloned_body->data_source.objid,
159                                  cloned_body->data_source.length,
160                                  body->data_source.objid,
161                                  body->data_source.length)) {
162                 ag_trace
163                     ("can't change historyControlDataSource - not Creation");
164                 return SNMP_ERR_BADVALUE;
165             }
166             break;
167         case Leaf_historyControlBucketsRequested:
168             snmp_status = AGUTIL_get_int_value(var_val, var_val_type,
169                                                var_val_len,
170                                                MIN_historyControlBucketsRequested,
171                                                MAX_historyControlBucketsRequested,
172                                                &cloned_body->scrlr.
173                                                data_requested);
174             if (SNMP_ERR_NOERROR != snmp_status) {
175                 return snmp_status;
176             }
177 #if 0
178             if (RMON1_ENTRY_UNDER_CREATION != hdr->status &&
179                 cloned_body->scrlr.data_requested !=
180                 body->scrlr.data_requested)
181                 return SNMP_ERR_BADVALUE;
182 #endif
183             break;
184         case Leaf_historyControlInterval:
185             snmp_status = AGUTIL_get_int_value(var_val, var_val_type,
186                                                var_val_len,
187                                                MIN_historyControlInterval,
188                                                MAX_historyControlInterval,
189                                                &cloned_body->interval);
190             if (SNMP_ERR_NOERROR != snmp_status) {
191                 return snmp_status;
192             }
193 #if 0
194             if (RMON1_ENTRY_UNDER_CREATION != hdr->status &&
195                 cloned_body->interval != body->interval)
196                 return SNMP_ERR_BADVALUE;
197 #endif
198             break;
199         case Leaf_historyControlOwner:
200             if (hdr->new_owner)
201                 AGFREE(hdr->new_owner);
202             hdr->new_owner = AGMALLOC(MAX_OWNERSTRING);;
203             if (!hdr->new_owner)
204                 return SNMP_ERR_TOOBIG;
205             snmp_status = AGUTIL_get_string_value(var_val, var_val_type,
206                                                   var_val_len,
207                                                   MAX_OWNERSTRING,
208                                                   1, NULL, hdr->new_owner);
209             if (SNMP_ERR_NOERROR != snmp_status) {
210                 return snmp_status;
211             }
212
213             break;
214         case Leaf_historyControlStatus:
215             snmp_status = AGUTIL_get_int_value(var_val, var_val_type,
216                                                var_val_len,
217                                                RMON1_ENTRY_VALID,
218                                                RMON1_ENTRY_INVALID,
219                                                &long_temp);
220             if (SNMP_ERR_NOERROR != snmp_status) {
221                 return snmp_status;
222             }
223             hdr->new_status = long_temp;
224             break;
225         default:
226             ag_trace("%s:unknown leaf_id=%d\n", table_ptr->name,
227                      (int) leaf_id);
228             return SNMP_ERR_NOSUCHNAME;
229         }                       /* of switch by 'leaf_id' */
230         break;
231
232     }                           /* of switch by actions */
233
234     prev_action = action;
235     return SNMP_ERR_NOERROR;
236 }
237
238 /*
239  * var_historyControlTable():
240  */
241 unsigned char  *
242 var_historyControlTable(struct variable *vp,
243                         oid * name,
244                         size_t * length,
245                         int exact,
246                         size_t * var_len, WriteMethod ** write_method)
247 {
248     static long     long_ret;
249     static CRTL_ENTRY_T theEntry;
250     RMON_ENTRY_T   *hdr;
251
252     *write_method = write_historyControl;
253     hdr = ROWAPI_header_ControlEntry(vp, name, length, exact, var_len,
254                                      table_ptr,
255                                      &theEntry, sizeof(CRTL_ENTRY_T));
256     if (!hdr)
257         return NULL;
258
259     *var_len = sizeof(long);    /* default */
260
261     switch (vp->magic) {
262     case CTRL_INDEX:
263         long_ret = hdr->ctrl_index;
264         return (unsigned char *) &long_ret;
265
266     case CTRL_DATASOURCE:
267         *var_len = sizeof(oid) * theEntry.data_source.length;
268         return (unsigned char *) theEntry.data_source.objid;
269
270     case CTRL_BUCKETSREQUESTED:
271         long_ret = theEntry.scrlr.data_requested;
272         return (unsigned char *) &long_ret;
273
274     case CTRL_BUCKETSGRANTED:
275
276         long_ret = theEntry.scrlr.data_granted;
277         return (unsigned char *) &long_ret;
278
279     case CTRL_INTERVAL:
280         long_ret = theEntry.interval;
281         return (unsigned char *) &long_ret;
282
283     case CTRL_OWNER:
284         if (hdr->owner) {
285             *var_len = strlen(hdr->owner);
286             return (unsigned char *) hdr->owner;
287         } else {
288             *var_len = 0;
289             return (unsigned char *) "";
290         }
291
292     case CTRL_STATUS:
293         long_ret = hdr->status;
294         return (unsigned char *) &long_ret;
295
296     default:
297         ag_trace("HistoryControlTable: unknown vp->magic=%d",
298                  (int) vp->magic);
299         ERROR_MSG("");
300     }
301     return NULL;
302 }
303
304 /*
305  * history row management control callbacks 
306  */
307
308 static void
309 compute_delta(ETH_STATS_T * delta,
310               ETH_STATS_T * newval, ETH_STATS_T * prevval)
311 {
312 #define CNT_DIF(X) delta->X = newval->X - prevval->X
313
314     CNT_DIF(octets);
315     CNT_DIF(packets);
316     CNT_DIF(bcast_pkts);
317     CNT_DIF(mcast_pkts);
318     CNT_DIF(crc_align);
319     CNT_DIF(undersize);
320     CNT_DIF(oversize);
321     CNT_DIF(fragments);
322     CNT_DIF(jabbers);
323     CNT_DIF(collisions);
324 }
325
326 static void
327 history_get_backet(unsigned int clientreg, void *clientarg)
328 {
329     RMON_ENTRY_T   *hdr_ptr;
330     CRTL_ENTRY_T   *body;
331     DATA_ENTRY_T   *bptr;
332     ETH_STATS_T     newSample;
333
334     /*
335      * ag_trace ("history_get_backet: timer_id=%d", (int) clientreg); 
336      */
337     hdr_ptr = (RMON_ENTRY_T *) clientarg;
338     if (!hdr_ptr) {
339         ag_trace
340             ("Err: history_get_backet: hdr_ptr=NULL ? (Inserted in shock)");
341         return;
342     }
343
344     body = (CRTL_ENTRY_T *) hdr_ptr->body;
345     if (!body) {
346         ag_trace
347             ("Err: history_get_backet: body=NULL ? (Inserted in shock)");
348         return;
349     }
350
351     if (RMON1_ENTRY_VALID != hdr_ptr->status) {
352         ag_trace("Err: history_get_backet when entry %d is not valid ?!!",
353                  (int) hdr_ptr->ctrl_index);
354         /*
355          * snmp_alarm_print_list (); 
356          */
357         snmp_alarm_unregister(body->timer_id);
358         ag_trace("Err: unregistered %ld", (long) body->timer_id);
359         return;
360     }
361
362     SYSTEM_get_eth_statistics(&body->data_source, &newSample);
363
364     bptr = ROWDATAAPI_locate_new_data(&body->scrlr);
365     if (!bptr) {
366         ag_trace
367             ("Err: history_get_backet for %d: empty bucket's list !??\n",
368              (int) hdr_ptr->ctrl_index);
369         return;
370     }
371
372     bptr->data_index = ROWDATAAPI_get_total_number(&body->scrlr);
373
374     bptr->start_interval = body->previous_bucket.start_interval;
375
376     compute_delta(&bptr->EthData, &newSample,
377                   &body->previous_bucket.EthData);
378
379     bptr->utilization =
380         bptr->EthData.octets * 8 + bptr->EthData.packets * (96 + 64);
381     bptr->utilization /= body->coeff;
382
383     /*
384      * update previous_bucket 
385      */
386     body->previous_bucket.start_interval = AGUTIL_sys_up_time();
387     memcpy(&body->previous_bucket.EthData, &newSample,
388            sizeof(ETH_STATS_T));
389 }
390
391 /*
392  * Control Table RowApi Callbacks 
393  */
394
395 int
396 history_Create(RMON_ENTRY_T * eptr)
397 {                               /* create the body: alloc it and set defaults */
398     CRTL_ENTRY_T   *body;
399
400     eptr->body = AGMALLOC(sizeof(CRTL_ENTRY_T));
401     if (!eptr->body)
402         return -3;
403     body = (CRTL_ENTRY_T *) eptr->body;
404
405     /*
406      * set defaults 
407      */
408     body->interval = HIST_DEF_INTERVAL;
409     body->timer_id = 0;
410     memcpy(&body->data_source, &DEFAULT_DATA_SOURCE, sizeof(VAR_OID_T));
411
412     ROWDATAAPI_init(&body->scrlr, HIST_DEF_BUCK_REQ,
413                     MAX_BUCKETS_IN_CRTL_ENTRY, sizeof(DATA_ENTRY_T), NULL);
414
415     return 0;
416 }
417
418 int
419 history_Validate(RMON_ENTRY_T * eptr)
420 {
421     /*
422      * T.B.D. (system dependent) check valid inteface in body->data_source; 
423      */
424     return 0;
425 }
426
427 int
428 history_Activate(RMON_ENTRY_T * eptr)
429 {
430     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
431
432     body->coeff = 100000L * (long) body->interval;
433
434     ROWDATAAPI_set_size(&body->scrlr,
435                         body->scrlr.data_requested,
436                         RMON1_ENTRY_VALID == eptr->status);
437
438     SYSTEM_get_eth_statistics(&body->data_source,
439                               &body->previous_bucket.EthData);
440     body->previous_bucket.start_interval = AGUTIL_sys_up_time();
441
442     body->scrlr.current_data_ptr = body->scrlr.first_data_ptr;
443     /*
444      * ag_trace ("Dbg:   registered in history_Activate"); 
445      */
446     body->timer_id = snmp_alarm_register(body->interval, SA_REPEAT,
447                                          history_get_backet, eptr);
448     return 0;
449 }
450
451 int
452 history_Deactivate(RMON_ENTRY_T * eptr)
453 {
454     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
455
456     snmp_alarm_unregister(body->timer_id);
457     /*
458      * ag_trace ("Dbg: unregistered in history_Deactivate timer_id=%d",
459      * (int) body->timer_id); 
460      */
461
462     /*
463      * free data list 
464      */
465     ROWDATAAPI_descructor(&body->scrlr);
466
467     return 0;
468 }
469
470 int
471 history_Copy(RMON_ENTRY_T * eptr)
472 {
473     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
474     CRTL_ENTRY_T   *clone = (CRTL_ENTRY_T *) eptr->tmp;
475
476     if (body->scrlr.data_requested != clone->scrlr.data_requested) {
477         ROWDATAAPI_set_size(&body->scrlr, clone->scrlr.data_requested,
478                             RMON1_ENTRY_VALID == eptr->status);
479     }
480
481     if (body->interval != clone->interval) {
482         if (RMON1_ENTRY_VALID == eptr->status) {
483             snmp_alarm_unregister(body->timer_id);
484             body->timer_id =
485                 snmp_alarm_register(clone->interval, SA_REPEAT,
486                                     history_get_backet, eptr);
487         }
488
489         body->interval = clone->interval;
490     }
491
492     if (snmp_oid_compare
493         (clone->data_source.objid, clone->data_source.length,
494          body->data_source.objid, body->data_source.length)) {
495         memcpy(&body->data_source, &clone->data_source, sizeof(VAR_OID_T));
496     }
497
498     return 0;
499 }
500
501 static SCROLLER_T *
502 history_extract_scroller(void *v_body)
503 {
504     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) v_body;
505     return &body->scrlr;
506 }
507
508 /*
509  * var_etherHistoryTable():
510  */
511 unsigned char  *
512 var_etherHistoryTable(struct variable *vp,
513                       oid * name,
514                       size_t * length,
515                       int exact,
516                       size_t * var_len, WriteMethod ** write_method)
517 {
518     static long     long_ret;
519     static DATA_ENTRY_T theBucket;
520     RMON_ENTRY_T   *hdr;
521     CRTL_ENTRY_T   *ctrl;
522
523     *write_method = NULL;
524     hdr = ROWDATAAPI_header_DataEntry(vp, name, length, exact, var_len,
525                                       table_ptr,
526                                       &history_extract_scroller,
527                                       sizeof(DATA_ENTRY_T), &theBucket);
528     if (!hdr)
529         return NULL;
530
531     *var_len = sizeof(long);    /* default */
532
533     ctrl = (CRTL_ENTRY_T *) hdr->body;
534
535     switch (vp->magic) {
536     case DATA_INDEX:
537         long_ret = hdr->ctrl_index;
538         return (unsigned char *) &long_ret;
539     case DATA_SAMPLEINDEX:
540         long_ret = theBucket.data_index;
541         return (unsigned char *) &long_ret;
542     case DATA_INTERVALSTART:
543         long_ret = 0;
544         return (unsigned char *) &theBucket.start_interval;
545     case DATA_DROPEVENTS:
546         long_ret = 0;
547         return (unsigned char *) &long_ret;
548     case DATA_OCTETS:
549         long_ret = 0;
550         return (unsigned char *) &theBucket.EthData.octets;
551     case DATA_PKTS:
552         long_ret = 0;
553         return (unsigned char *) &theBucket.EthData.packets;
554     case DATA_BROADCASTPKTS:
555         long_ret = 0;
556         return (unsigned char *) &theBucket.EthData.bcast_pkts;
557     case DATA_MULTICASTPKTS:
558         long_ret = 0;
559         return (unsigned char *) &theBucket.EthData.mcast_pkts;
560     case DATA_CRCALIGNERRORS:
561         long_ret = 0;
562         return (unsigned char *) &theBucket.EthData.crc_align;
563     case DATA_UNDERSIZEPKTS:
564         long_ret = 0;
565         return (unsigned char *) &theBucket.EthData.undersize;
566     case DATA_OVERSIZEPKTS:
567         long_ret = 0;
568         return (unsigned char *) &theBucket.EthData.oversize;
569     case DATA_FRAGMENTS:
570         long_ret = 0;
571         return (unsigned char *) &theBucket.EthData.fragments;
572     case DATA_JABBERS:
573         long_ret = 0;
574         return (unsigned char *) &theBucket.EthData.jabbers;
575     case DATA_COLLISIONS:
576         long_ret = 0;
577         return (unsigned char *) &theBucket.EthData.collisions;
578     case DATA_UTILIZATION:
579         long_ret = 0;
580         return (unsigned char *) &theBucket.utilization;
581     default:
582         ag_trace("etherHistoryTable: unknown vp->magic=%d",
583                  (int) vp->magic);
584         ERROR_MSG("");
585     }
586     return NULL;
587 }
588
589 #if 1                           /* debug, but may be used for init. TBD: may be token snmpd.conf ? */
590 int
591 add_hist_entry(int ctrl_index, int ifIndex,
592                u_long interval, u_long requested)
593 {
594     register RMON_ENTRY_T *eptr;
595     register CRTL_ENTRY_T *body;
596     int             ierr;
597
598     ierr = ROWAPI_new(table_ptr, ctrl_index);
599     if (ierr) {
600         ag_trace("ROWAPI_new failed with %d", ierr);
601         return ierr;
602     }
603
604     eptr = ROWAPI_find(table_ptr, ctrl_index);
605     if (!eptr) {
606         ag_trace("ROWAPI_find failed");
607         return -4;
608     }
609
610     body = (CRTL_ENTRY_T *) eptr->body;
611
612     /*
613      * set parameters 
614      */
615
616     body->data_source.objid[body->data_source.length - 1] = ifIndex;
617     body->interval = interval;
618     body->scrlr.data_requested = requested;
619
620     eptr->new_status = RMON1_ENTRY_VALID;
621     ierr = ROWAPI_commit(table_ptr, ctrl_index);
622     if (ierr) {
623         ag_trace("ROWAPI_commit failed with %d", ierr);
624     }
625
626     return ierr;
627
628 }
629
630 #endif
631
632 /*
633  * Registration & Initializatio section 
634  */
635
636 oid             historyControlTable_variables_oid[] =
637     { 1, 3, 6, 1, 2, 1, 16, 2, 1 };
638
639 struct variable2 historyControlTable_variables[] = {
640     /*
641      * magic number        , variable type, ro/rw , callback fn  ,           L, oidsuffix 
642      */
643     {CTRL_INDEX, ASN_INTEGER, RONLY, var_historyControlTable, 2, {1, 1}},
644     {CTRL_DATASOURCE, ASN_OBJECT_ID, RWRITE, var_historyControlTable, 2,
645      {1, 2}},
646     {CTRL_BUCKETSREQUESTED, ASN_INTEGER, RWRITE, var_historyControlTable,
647      2, {1, 3}},
648     {CTRL_BUCKETSGRANTED, ASN_INTEGER, RONLY, var_historyControlTable, 2,
649      {1, 4}},
650     {CTRL_INTERVAL, ASN_INTEGER, RWRITE, var_historyControlTable, 2,
651      {1, 5}},
652     {CTRL_OWNER, ASN_OCTET_STR, RWRITE, var_historyControlTable, 2,
653      {1, 6}},
654     {CTRL_STATUS, ASN_INTEGER, RWRITE, var_historyControlTable, 2, {1, 7}},
655
656 };
657
658 oid             etherHistoryTable_variables_oid[] =
659     { 1, 3, 6, 1, 2, 1, 16, 2, 2 };
660
661 struct variable2 etherHistoryTable_variables[] = {
662     /*
663      * magic number     , variable type , ro/rw , callback fn  ,        L, oidsuffix 
664      */
665     {DATA_INDEX, ASN_INTEGER, RONLY, var_etherHistoryTable, 2, {1, 1}},
666     {DATA_SAMPLEINDEX, ASN_INTEGER, RONLY, var_etherHistoryTable, 2,
667      {1, 2}},
668     {DATA_INTERVALSTART, ASN_TIMETICKS, RONLY, var_etherHistoryTable, 2,
669      {1, 3}},
670     {DATA_DROPEVENTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
671      {1, 4}},
672     {DATA_OCTETS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2, {1, 5}},
673     {DATA_PKTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2, {1, 6}},
674     {DATA_BROADCASTPKTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
675      {1, 7}},
676     {DATA_MULTICASTPKTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
677      {1, 8}},
678     {DATA_CRCALIGNERRORS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
679      {1, 9}},
680     {DATA_UNDERSIZEPKTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
681      {1, 10}},
682     {DATA_OVERSIZEPKTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
683      {1, 11}},
684     {DATA_FRAGMENTS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
685      {1, 12}},
686     {DATA_JABBERS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2, {1, 13}},
687     {DATA_COLLISIONS, ASN_COUNTER, RONLY, var_etherHistoryTable, 2,
688      {1, 14}},
689     {DATA_UTILIZATION, ASN_INTEGER, RONLY, var_etherHistoryTable, 2,
690      {1, 15}},
691
692 };
693
694 void
695 init_history(void)
696 {
697     REGISTER_MIB("historyControlTable", historyControlTable_variables,
698                  variable2, historyControlTable_variables_oid);
699     REGISTER_MIB("etherHistoryTable", etherHistoryTable_variables,
700                  variable2, etherHistoryTable_variables_oid);
701
702     ROWAPI_init_table(&HistoryCtrlTable, "History", 0, &history_Create, NULL,   /* &history_Clone, */
703                       NULL,     /* &history_Delete, */
704                       &history_Validate,
705                       &history_Activate,
706                       &history_Deactivate, &history_Copy);
707
708     /*
709      * add_hist_entry (2, 3, 4, 2); 
710      */
711 }