1 /**************************************************************
2  * Copyright (C) 2001 Tali 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  * TALI 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 <net-snmp/net-snmp-config.h>
22 
23 #if HAVE_STDLIB
24 #include <stdlib.h>
25 #endif
26 #if TIME_WITH_SYS_TIME
27 # include <sys/time.h>
28 # include <time.h>
29 #else
30 # if HAVE_SYS_TIME_H
31 #  include <sys/time.h>
32 # else
33 #  include <time.h>
34 # endif
35 #endif
36 #if HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 
40 #include <net-snmp/net-snmp-includes.h>
41 #include <net-snmp/agent/net-snmp-agent-includes.h>
42 #include "statistics.h"
43         /*
44          * Implementation headers
45          */
46 #include "agutil_api.h"
47 #include "row_api.h"
48         /*
49          * File scope definitions section
50          */
51         /*
52          * from MIB compilation
53          */
54 #define MIB_DESCR	"EthStat"
55 #define etherStatsEntryFirstIndexBegin	11
56 #define IDetherStatsDroppedFrames        1
57 #define IDetherStatsCreateTime           2
58 #define IDetherStatsIndex                3
59 #define IDetherStatsDataSource           4
60 #define IDetherStatsDropEvents           5
61 #define IDetherStatsOctets               6
62 #define IDetherStatsPkts                 7
63 #define IDetherStatsBroadcastPkts        8
64 #define IDetherStatsMulticastPkts        9
65 #define IDetherStatsCRCAlignErrors       10
66 #define IDetherStatsUndersizePkts        11
67 #define IDetherStatsOversizePkts         12
68 #define IDetherStatsFragments            13
69 #define IDetherStatsJabbers              14
70 #define IDetherStatsCollisions           15
71 #define IDetherStatsPkts64Octets         16
72 #define IDetherStatsPkts65to127Octets    17
73 #define IDetherStatsPkts128to255Octets   18
74 #define IDetherStatsPkts256to511Octets   19
75 #define IDetherStatsPkts512to1023Octets  20
76 #define IDetherStatsPkts1024to1518Octets 21
77 #define IDetherStatsOwner                22
78 #define IDetherStatsStatus               23
79 #define Leaf_etherStatsDataSource        2
80 #define Leaf_etherStatsOwner             20
81 #define Leaf_etherStatsStatus            21
82 #define MIN_etherStatsIndex   1
83 #define MAX_etherStatsIndex   65535
84      typedef struct {
85          VAR_OID_T
86              data_source;
87          u_long
88              etherStatsCreateTime;
89          ETH_STATS_T
90              eth;
91      } CRTL_ENTRY_T;
92 
93 /*
94  * Main section
95  */
96 
97      static TABLE_DEFINTION_T
98          StatCtrlTable;
99      static TABLE_DEFINTION_T *
100          table_ptr = &
101          StatCtrlTable;
102 
103 /*
104  * Control Table RowApi Callbacks
105  */
106 
107      int
stat_Create(RMON_ENTRY_T * eptr)108      stat_Create(RMON_ENTRY_T * eptr)
109 {                               /* create the body: alloc it and set defaults */
110     CRTL_ENTRY_T   *body;
111     static VAR_OID_T data_src_if_index_1 =
112         { 11, {1, 3, 6, 1, 2, 1, 2, 2, 1, 1, 1} };
113 
114     eptr->body = AGMALLOC(sizeof(CRTL_ENTRY_T));
115     if (!eptr->body)
116         return -3;
117     body = (CRTL_ENTRY_T *) eptr->body;
118 
119     /*
120      * set defaults
121      */
122     memcpy(&body->data_source, &data_src_if_index_1, sizeof(VAR_OID_T));
123     body->data_source.objid[body->data_source.length - 1] =
124         eptr->ctrl_index;
125     eptr->owner = AGSTRDUP("Startup Mgmt");
126     memset(&body->eth, 0, sizeof(ETH_STATS_T));
127 
128     return 0;
129 }
130 
131 int
stat_Validate(RMON_ENTRY_T * eptr)132 stat_Validate(RMON_ENTRY_T * eptr)
133 {
134     /*
135      * T.B.D. (system dependent) check valid inteface in body->data_source;
136      */
137 
138     return 0;
139 }
140 
141 int
stat_Activate(RMON_ENTRY_T * eptr)142 stat_Activate(RMON_ENTRY_T * eptr)
143 {
144     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
145 
146     body->etherStatsCreateTime = AGUTIL_sys_up_time();
147 
148     return 0;
149 }
150 
151 int
stat_Copy(RMON_ENTRY_T * eptr)152 stat_Copy(RMON_ENTRY_T * eptr)
153 {
154     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
155     CRTL_ENTRY_T   *clone = (CRTL_ENTRY_T *) eptr->tmp;
156 
157     if (snmp_oid_compare
158         (clone->data_source.objid, clone->data_source.length,
159          body->data_source.objid, body->data_source.length)) {
160         memcpy(&body->data_source, &clone->data_source, sizeof(VAR_OID_T));
161     }
162 
163     return 0;
164 }
165 
166 int
stat_Deactivate(RMON_ENTRY_T * eptr)167 stat_Deactivate(RMON_ENTRY_T * eptr)
168 {
169     CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
170     memset(&body->eth, 0, sizeof(ETH_STATS_T));
171     return 0;
172 }
173 
174 
175 /***************************************************
176  * Function:var_etherStats2Entry
177  * Purpose: Handles the request for etherStats2Entry variable instances
178  ***************************************************/
179 u_char         *
var_etherStats2Entry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)180 var_etherStats2Entry(struct variable * vp, oid * name, size_t * length,
181                      int exact, size_t * var_len,
182                      WriteMethod ** write_method)
183 {
184     static long     long_return;
185     static CRTL_ENTRY_T theEntry;
186     RMON_ENTRY_T   *hdr;
187 
188     *write_method = NULL;
189 
190     hdr = ROWAPI_header_ControlEntry(vp, name, length, exact, var_len,
191                                      table_ptr,
192                                      &theEntry, sizeof(CRTL_ENTRY_T));
193     if (!hdr)
194         return NULL;
195 
196     *var_len = sizeof(long);    /* default */
197 
198     switch (vp->magic) {
199     case IDetherStatsDroppedFrames:
200         long_return = 0;
201         return (u_char *) & long_return;
202     case IDetherStatsCreateTime:
203         long_return = theEntry.etherStatsCreateTime;
204         return (u_char *) & long_return;
205     default:
206         ag_trace("%s: unknown vp->magic=%d", table_ptr->name,
207                  (int) vp->magic);
208         ERROR_MSG("");
209     };                          /* of switch by 'vp->magic'  */
210 
211     return NULL;
212 }
213 
214 
215 /***************************************************
216  * Function:write_etherStatsEntry
217  ***************************************************/
218 static int
write_etherStatsEntry(int action,u_char * var_val,u_char var_val_type,size_t var_val_len,u_char * statP,oid * name,size_t name_len)219 write_etherStatsEntry(int action, u_char * var_val, u_char var_val_type,
220                       size_t var_val_len, u_char * statP,
221                       oid * name, size_t name_len)
222 {
223     long            long_temp;
224     int             leaf_id, snmp_status;
225     static int      prev_action = COMMIT;
226     RMON_ENTRY_T   *hdr;
227     CRTL_ENTRY_T   *cloned_body;
228     CRTL_ENTRY_T   *body;
229 
230     switch (action) {
231     case RESERVE1:
232     case FREE:
233     case UNDO:
234     case ACTION:
235     case COMMIT:
236     default:
237         snmp_status =
238             ROWAPI_do_another_action(name, etherStatsEntryFirstIndexBegin,
239                                      action, &prev_action, table_ptr,
240                                      sizeof(CRTL_ENTRY_T));
241         if (SNMP_ERR_NOERROR != snmp_status) {
242             ag_trace("failed action %d with %d", action, snmp_status);
243         }
244         break;
245 
246     case RESERVE2:
247         /*
248          * get values from PDU, check them and save them in the cloned entry
249          */
250         long_temp = name[etherStatsEntryFirstIndexBegin];
251         leaf_id = (int) name[etherStatsEntryFirstIndexBegin - 1];
252         hdr = ROWAPI_find(table_ptr, long_temp);        /* it MUST be OK */
253         cloned_body = (CRTL_ENTRY_T *) hdr->tmp;
254         body = (CRTL_ENTRY_T *) hdr->body;
255         switch (leaf_id) {
256         case Leaf_etherStatsDataSource:
257             snmp_status = AGUTIL_get_oid_value(var_val, var_val_type,
258                                                var_val_len,
259                                                &cloned_body->data_source);
260             if (SNMP_ERR_NOERROR != snmp_status) {
261                 return snmp_status;
262             }
263             if (RMON1_ENTRY_UNDER_CREATION != hdr->status &&
264                 snmp_oid_compare(cloned_body->data_source.objid,
265                                  cloned_body->data_source.length,
266                                  body->data_source.objid,
267                                  body->data_source.length))
268                 return SNMP_ERR_BADVALUE;
269             break;
270 
271             break;
272         case Leaf_etherStatsOwner:
273             if (hdr->new_owner)
274                 AGFREE(hdr->new_owner);
275             hdr->new_owner = AGMALLOC(MAX_OWNERSTRING);
276             if (!hdr->new_owner)
277                 return SNMP_ERR_TOOBIG;
278             snmp_status = AGUTIL_get_string_value(var_val, var_val_type,
279                                                   var_val_len,
280                                                   MAX_OWNERSTRING,
281                                                   1, NULL, hdr->new_owner);
282             if (SNMP_ERR_NOERROR != snmp_status) {
283                 return snmp_status;
284             }
285             break;
286         case Leaf_etherStatsStatus:
287             snmp_status = AGUTIL_get_int_value(var_val, var_val_type,
288                                                var_val_len,
289                                                RMON1_ENTRY_VALID,
290                                                RMON1_ENTRY_INVALID,
291                                                &long_temp);
292             if (SNMP_ERR_NOERROR != snmp_status) {
293                 ag_trace("cannot browse etherStatsStatus");
294                 return snmp_status;
295             }
296             hdr->new_status = long_temp;
297             break;
298             break;
299         default:
300             ag_trace("%s:unknown leaf_id=%d\n", table_ptr->name,
301                      (int) leaf_id);
302             return SNMP_ERR_NOSUCHNAME;
303         }                       /* of switch by 'leaf_id' */
304         break;
305     }                           /* of switch by 'action' */
306 
307     prev_action = action;
308     return SNMP_ERR_NOERROR;
309 }
310 
311 /***************************************************
312  * Function:var_etherStatsEntry
313  * Purpose: Handles the request for etherStatsEntry variable instances
314  ***************************************************/
315 u_char         *
var_etherStatsEntry(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)316 var_etherStatsEntry(struct variable * vp, oid * name, size_t * length,
317                     int exact, size_t * var_len,
318                     WriteMethod ** write_method)
319 {
320     static unsigned char zero_octet_string[1];
321     static long     long_return;
322     static CRTL_ENTRY_T theEntry;
323     RMON_ENTRY_T   *hdr;
324 
325     *write_method = write_etherStatsEntry;
326     hdr = ROWAPI_header_ControlEntry(vp, name, length, exact, var_len,
327                                      table_ptr,
328                                      &theEntry, sizeof(CRTL_ENTRY_T));
329     if (!hdr)
330         return NULL;
331 
332     if (RMON1_ENTRY_VALID == hdr->status)
333         SYSTEM_get_eth_statistics(&theEntry.data_source, &theEntry.eth);
334 
335     *var_len = sizeof(long);
336 
337     switch (vp->magic) {
338     case IDetherStatsIndex:
339         long_return = hdr->ctrl_index;
340         return (u_char *) & long_return;
341     case IDetherStatsDataSource:
342         *var_len = sizeof(oid) * theEntry.data_source.length;
343         return (unsigned char *) theEntry.data_source.objid;
344     case IDetherStatsDropEvents:
345         long_return = 0;        /* theEntry.eth.etherStatsDropEvents; */
346         return (u_char *) & long_return;
347     case IDetherStatsOctets:
348         long_return = theEntry.eth.octets;
349         return (u_char *) & long_return;
350     case IDetherStatsPkts:
351         long_return = theEntry.eth.packets;
352         return (u_char *) & long_return;
353     case IDetherStatsBroadcastPkts:
354         long_return = theEntry.eth.bcast_pkts;
355         return (u_char *) & long_return;
356     case IDetherStatsMulticastPkts:
357         long_return = theEntry.eth.mcast_pkts;
358         return (u_char *) & long_return;
359     case IDetherStatsCRCAlignErrors:
360         long_return = theEntry.eth.crc_align;
361         return (u_char *) & long_return;
362     case IDetherStatsUndersizePkts:
363         long_return = theEntry.eth.undersize;
364         return (u_char *) & long_return;
365     case IDetherStatsOversizePkts:
366         long_return = theEntry.eth.oversize;
367         return (u_char *) & long_return;
368     case IDetherStatsFragments:
369         long_return = theEntry.eth.fragments;
370         return (u_char *) & long_return;
371     case IDetherStatsJabbers:
372         long_return = theEntry.eth.jabbers;
373         return (u_char *) & long_return;
374     case IDetherStatsCollisions:
375         long_return = theEntry.eth.collisions;
376         return (u_char *) & long_return;
377     case IDetherStatsPkts64Octets:
378         long_return = theEntry.eth.pkts_64;
379         return (u_char *) & long_return;
380     case IDetherStatsPkts65to127Octets:
381         long_return = theEntry.eth.pkts_65_127;
382         return (u_char *) & long_return;
383     case IDetherStatsPkts128to255Octets:
384         long_return = theEntry.eth.pkts_128_255;
385         return (u_char *) & long_return;
386     case IDetherStatsPkts256to511Octets:
387         long_return = theEntry.eth.pkts_256_511;
388         return (u_char *) & long_return;
389     case IDetherStatsPkts512to1023Octets:
390         long_return = theEntry.eth.pkts_512_1023;
391         return (u_char *) & long_return;
392     case IDetherStatsPkts1024to1518Octets:
393         long_return = theEntry.eth.pkts_1024_1518;
394         return (u_char *) & long_return;
395     case IDetherStatsOwner:
396         if (hdr->owner) {
397             *var_len = strlen(hdr->owner);
398             return (unsigned char *) hdr->owner;
399         } else {
400             *var_len = 0;
401             return zero_octet_string;
402         }
403     case IDetherStatsStatus:
404         long_return = hdr->status;
405         return (u_char *) & long_return;
406     default:
407         ERROR_MSG("");
408     };                          /* of switch by 'vp->magic'  */
409 
410     return NULL;
411 }
412 
413 #if 1                           /* debug, but may be used for init. TBD: may be token snmpd.conf ? */
414 int
add_statistics_entry(int ctrl_index,int ifIndex)415 add_statistics_entry(int ctrl_index, int ifIndex)
416 {
417     int             ierr;
418 
419     ierr = ROWAPI_new(table_ptr, ctrl_index);
420     switch (ierr) {
421     case -1:
422         ag_trace("max. number exedes\n");
423         break;
424     case -2:
425         ag_trace("malloc failed");
426         break;
427     case -3:
428         ag_trace("ClbkCreate failed");
429         break;
430     case 0:
431         break;
432     default:
433         ag_trace("Unknown code %d", ierr);
434         break;
435     }
436 
437     if (!ierr) {
438         register RMON_ENTRY_T *eptr = ROWAPI_find(table_ptr, ctrl_index);
439         if (!eptr) {
440             ag_trace("cannot find it");
441             ierr = -4;
442         } else {
443             CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
444 
445             body->data_source.objid[body->data_source.length - 1] =
446                 ifIndex;
447 
448             eptr->new_status = RMON1_ENTRY_VALID;
449             ierr = ROWAPI_commit(table_ptr, ctrl_index);
450             if (ierr) {
451                 ag_trace("ROWAPI_commit returned %d", ierr);
452             }
453         }
454     }
455 
456     return ierr;
457 }
458 #endif
459 
460 /***************************************************
461  * define Variables callbacks
462  ***************************************************/
463 oid             oidstatisticsVariablesOid[] = { 1, 3, 6, 1, 2, 1, 16, 1 };
464 
465 struct variable7 oidstatisticsVariables[] = {
466     {IDetherStatsIndex, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
467      var_etherStatsEntry, 3, {1, 1, 1}},
468     {IDetherStatsDataSource, ASN_OBJECT_ID, NETSNMP_OLDAPI_RWRITE,
469      var_etherStatsEntry, 3, {1, 1, 2}},
470     {IDetherStatsDropEvents, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
471      var_etherStatsEntry, 3, {1, 1, 3}},
472     {IDetherStatsOctets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
473      var_etherStatsEntry, 3, {1, 1, 4}},
474     {IDetherStatsPkts, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
475      var_etherStatsEntry, 3, {1, 1, 5}},
476     {IDetherStatsBroadcastPkts, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
477      var_etherStatsEntry, 3, {1, 1, 6}},
478     {IDetherStatsMulticastPkts, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
479      var_etherStatsEntry, 3, {1, 1, 7}},
480     {IDetherStatsCRCAlignErrors, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
481      var_etherStatsEntry, 3, {1, 1, 8}},
482     {IDetherStatsUndersizePkts, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
483      var_etherStatsEntry, 3, {1, 1, 9}},
484     {IDetherStatsOversizePkts, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
485      var_etherStatsEntry, 3, {1, 1, 10}},
486     {IDetherStatsFragments, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
487      var_etherStatsEntry, 3, {1, 1, 11}},
488     {IDetherStatsJabbers, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
489      var_etherStatsEntry, 3, {1, 1, 12}},
490     {IDetherStatsCollisions, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
491      var_etherStatsEntry, 3, {1, 1, 13}},
492     {IDetherStatsPkts64Octets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
493      var_etherStatsEntry, 3, {1, 1, 14}},
494     {IDetherStatsPkts65to127Octets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
495      var_etherStatsEntry, 3, {1, 1, 15}},
496     {IDetherStatsPkts128to255Octets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
497      var_etherStatsEntry, 3, {1, 1, 16}},
498     {IDetherStatsPkts256to511Octets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
499      var_etherStatsEntry, 3, {1, 1, 17}},
500     {IDetherStatsPkts512to1023Octets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
501      var_etherStatsEntry, 3, {1, 1, 18}},
502     {IDetherStatsPkts1024to1518Octets, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
503      var_etherStatsEntry, 3, {1, 1, 19}},
504     {IDetherStatsOwner, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE,
505      var_etherStatsEntry, 3, {1, 1, 20}},
506     {IDetherStatsStatus, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE,
507      var_etherStatsEntry, 3, {1, 1, 21}},
508     {IDetherStatsDroppedFrames, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
509      var_etherStats2Entry, 3, {4, 1, 1}},
510     {IDetherStatsCreateTime, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY,
511      var_etherStats2Entry, 3, {4, 1, 2}},
512 };
513 
514 /***************************************************
515  * Function:init_statistics
516  * Purpose: register statistics objects in the agent
517  ***************************************************/
518 void
init_statistics(void)519 init_statistics(void)
520 {
521     REGISTER_MIB(MIB_DESCR, oidstatisticsVariables, variable7,
522                  oidstatisticsVariablesOid);
523 
524     ROWAPI_init_table(&StatCtrlTable, MIB_DESCR, 0, &stat_Create, NULL, /* &stat_Clone, */
525                       NULL,     /* &stat_Delete, */
526                       &stat_Validate,
527                       &stat_Activate, &stat_Deactivate, &stat_Copy);
528 
529 #if 0                           /* debug */
530     {
531         int             iii;
532         for (iii = 1; iii < 6; iii++) {
533             add_statistics_entry(iii, iii);
534         }
535 
536         add_statistics_entry(10, 16);
537         add_statistics_entry(12, 11);
538     }
539 #endif
540 }
541 
542 /*
543  * end of file statistics.c
544  */
545