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