Imported Upstream version 0.4.8
[platform/upstream/libsmi.git] / tools / dump-sizes.c
1 /*
2  * dump-sizes.c --
3  *
4  *      Operations to compute and dump SNMPv3 PDU sizes.
5  *
6  * Copyright (c) 2003 J. Schoenwaelder, International University Bremen.
7  *
8  * See the file "COPYING" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * @(#) $Id: dump-sizes.c 8090 2008-04-18 12:56:29Z strauss $
12  */
13
14 #include <config.h>
15
16 #include <stdio.h>
17 #include <string.h>
18 #ifdef HAVE_WIN_H
19 #include "win.h"
20 #endif
21
22 #include "smi.h"
23 #include "smidump.h"
24
25 static int silent = 0;
26 static int detail = 0;
27
28 /*
29  * help functions
30  */
31 #define m_abs(a)        ((a) < 0 ? -(a) : (a))
32
33 typedef struct WellKnowType {
34     char *module;
35     char *name;
36     int max;
37     int mean;
38     int min;
39 } WellKnowType;
40
41 static WellKnowType specialTypes[] = {
42     { "SNMPv2-TC", "PhysAddress", 65535, 6, 0 },
43     { "INET-ADDRESS-MIB", "InetAddress", 255, 4, 0 },
44     { "IANATn3270eTC-MIB", "IANATn3270eAddress", 255, 4, 0 },
45     { NULL, NULL, 0, 0, 0 }
46 };
47
48
49
50 typedef enum len_type {
51     len_min,
52     len_mean,
53     len_max
54 } len_type;
55
56
57
58 static SmiInteger32
59 getAbsMinEnum(SmiType *smiType)
60 {
61      SmiNamedNumber *nn;
62      SmiInteger32 min = SMI_BASETYPE_INTEGER32_MAX;
63
64      for (nn = smiGetFirstNamedNumber(smiType);
65           nn;
66           nn = smiGetNextNamedNumber(nn)) {
67           if (abs(nn->value.value.integer32) < min) {
68                min = abs(nn->value.value.integer32);
69           }
70      }
71      return min;
72 }
73
74
75
76 static SmiInteger32
77 getAbsMaxEnum(SmiType *smiType)
78 {
79      SmiNamedNumber *nn;
80      SmiInteger32 max = 0;
81
82      for (nn = smiGetFirstNamedNumber(smiType);
83           nn;
84           nn = smiGetNextNamedNumber(nn)) {
85           if (abs(nn->value.value.integer32) > max) {
86                max = abs(nn->value.value.integer32);
87           }
88      }
89      return max;
90 }
91
92
93
94 static SmiInteger32
95 getAbsMinInteger32(SmiType *smiType)
96 {
97      SmiType *parent;
98      SmiRange *range;
99      SmiInteger32 min = SMI_BASETYPE_INTEGER32_MAX;
100
101      range = smiGetFirstRange(smiType);
102      if (! range) {
103           parent = smiGetParentType(smiType);
104           return parent ? getAbsMinInteger32(parent) : 0;
105      }
106
107      for (; range; range = smiGetNextRange(range)) {
108           if (abs(range->minValue.value.integer32) < min) {
109                min = abs(range->minValue.value.integer32);
110           }
111      }
112      return min;
113 }
114
115
116
117 static SmiInteger32
118 getAbsMaxInteger32(SmiType *smiType)
119 {
120      SmiType *parent;
121      SmiRange *range;
122      SmiInteger32 max = SMI_BASETYPE_INTEGER32_MIN;
123
124      range = smiGetFirstRange(smiType);
125      if (! range) {
126           parent = smiGetParentType(smiType);
127           return parent
128               ? getAbsMaxInteger32(parent) : SMI_BASETYPE_INTEGER32_MAX;
129      }
130
131      for (; range; range = smiGetNextRange(range)) {
132           if (abs(range->maxValue.value.integer32) > max) {
133                max = abs(range->maxValue.value.integer32);
134           }
135      }
136      return max;
137 }
138
139
140
141 static SmiUnsigned32
142 getMinUnsigned32(SmiType *smiType)
143 {
144      SmiType *parent;
145      SmiRange *range;
146      SmiInteger32 min = 0xffffffff;
147
148      range = smiGetFirstRange(smiType);
149      if (! range) {
150           parent = smiGetParentType(smiType);
151           return parent ? getMinUnsigned32(parent) : 0;
152      }
153
154      for (; range; range = smiGetNextRange(range)) {
155           if (range->minValue.value.unsigned32 < min) {
156                min = range->minValue.value.unsigned32;
157           }
158      }
159      return min;
160 }
161
162
163
164 static SmiUnsigned32
165 getMaxUnsigned32(SmiType *smiType)
166 {
167      SmiType *parent;
168      SmiRange *range;
169      SmiUnsigned32 max = 0;
170
171      range = smiGetFirstRange(smiType);
172      if (! range) {
173           parent = smiGetParentType(smiType);
174           return parent ? getMaxUnsigned32(parent) : 0xffffffff;
175      }
176
177      for (; range; range = smiGetNextRange(range)) {
178           if (range->maxValue.value.unsigned32 > max) {
179                max = range->maxValue.value.unsigned32;
180           }
181      }
182      return max;
183 }
184
185
186
187 static SmiInteger64
188 getAbsMinInteger64(SmiType *smiType)
189 {
190      SmiType *parent;
191      SmiRange *range;
192      SmiInteger64 min = SMI_BASETYPE_INTEGER64_MAX;
193
194      range = smiGetFirstRange(smiType);
195      if (! range) {
196           parent = smiGetParentType(smiType);
197           return parent ? getAbsMinInteger64(parent) : min;
198      }
199
200      for (; range; range = smiGetNextRange(range)) {
201           if (m_abs(range->minValue.value.integer64) < min) {
202                min = m_abs(range->minValue.value.integer64);
203           }
204      }
205      return min;
206 }
207
208
209
210 static SmiInteger64
211 getAbsMaxInteger64(SmiType *smiType)
212 {
213      SmiType *parent;
214      SmiRange *range;
215      SmiInteger64 max = SMI_BASETYPE_INTEGER64_MIN;
216
217      range = smiGetFirstRange(smiType);
218      if (! range) {
219           parent = smiGetParentType(smiType);
220           return parent ? getAbsMaxInteger64(parent) : max;
221      }
222
223      for (; range; range = smiGetNextRange(range)) {
224           if (m_abs(range->maxValue.value.integer64) > max) {
225                max = m_abs(range->maxValue.value.integer64);
226           }
227      }
228      return max;
229 }
230
231
232
233 static SmiUnsigned64
234 getMinUnsigned64(SmiType *smiType)
235 {
236      SmiType *parent;
237      SmiRange *range;
238      SmiInteger64 min = SMI_BASETYPE_UNSIGNED64_MAX;
239
240      range = smiGetFirstRange(smiType);
241      if (! range) {
242           parent = smiGetParentType(smiType);
243           return parent ? getMinUnsigned64(parent) : min;
244      }
245
246      for (; range; range = smiGetNextRange(range)) {
247           if (range->minValue.value.unsigned64 < min) {
248                min = range->minValue.value.unsigned64;
249           }
250      }
251      return min;
252 }
253
254
255
256 static SmiUnsigned64
257 getMaxUnsigned64(SmiType *smiType)
258 {
259      SmiType *parent;
260      SmiRange *range;
261      SmiUnsigned64 max = SMI_BASETYPE_UNSIGNED64_MIN;
262
263      range = smiGetFirstRange(smiType);
264      if (! range) {
265           parent = smiGetParentType(smiType);
266           return parent ? getMaxUnsigned64(parent) : max;
267      }
268
269      for (; range; range = smiGetNextRange(range)) {
270           if (range->maxValue.value.unsigned64 > max) {
271                max = range->maxValue.value.unsigned64;
272           }
273      }
274      return max;
275 }
276
277
278
279 static int
280 ber_len_length(int length)
281 {
282      int len;
283      
284      if (length < 0x80) {
285           return 1;
286      }
287
288      for (len = 0; length > 0; len++) {
289           length >>= 8;
290      }
291      return len;
292 }
293
294
295
296 static int
297 ber_len_subid(SmiSubid subid)
298 {
299      int len = 0;
300
301      do {
302           subid >>= 7;
303           len++;
304      } while (subid > 0);
305      return len;
306 }
307
308
309
310 static int
311 ber_len_oid(const SmiSubid *oid, unsigned int oidlen)
312 {
313      int len = 0;
314      int i;
315      
316      len += ber_len_subid(oid[1] + oid[0] * 40);
317      for (i = 2; i < oidlen; i++) {
318           len += ber_len_subid(oid[i]);
319      }
320
321      len += ber_len_length(len);        /* length */
322      len += 1;                          /* tag */
323      return len;
324 }
325
326
327
328 static int
329 ber_len_int32(const SmiInteger32 value)
330 {
331      SmiInteger32 val = value;
332      unsigned char ch, sign;
333      int lim;
334      int len = 0;
335      
336      if (val < 0) {
337           lim  = -1;
338           sign = 0x80;
339      } else {
340           lim  = 0;
341           sign = 0x00;
342      }
343      do {
344           ch = (unsigned char) val;
345           val >>= 8;
346           len++;
347      } while ((val != lim) || (unsigned char) (ch & 0x80) != sign);
348
349      len += ber_len_length(len);        /* length */
350      len += 1;                          /* tag */
351      return len;
352 }
353
354
355
356 static int
357 ber_len_uint32(const SmiUnsigned32 value)
358 {
359      SmiUnsigned32 val = value;
360      unsigned char ch;
361      int len = 0;
362      
363      do {
364           ch = (unsigned char) val;
365           val >>= 8;
366           len++;
367      } while ((val != 0) || (ch & 0x80) != 0x00);
368
369      len += ber_len_length(len);        /* length */
370      len += 1;                          /* tag */
371      return len;
372 }
373
374
375
376 static int
377 ber_len_int64(const SmiInteger64 value)
378 {
379      SmiInteger64 val = value;
380      unsigned char ch, sign;
381      int lim;
382      int len = 0;
383      
384      if (val < 0) {
385           lim  = -1;
386           sign = 0x80;
387      } else {
388           lim  = 0;
389           sign = 0x00;
390      }
391      do {
392           ch = (unsigned char) val;
393           val >>= 8;
394           len++;
395      } while ((val != lim) || (unsigned char) (ch & 0x80) != sign);
396
397      len += ber_len_length(len);        /* length */
398      len += 1;                          /* tag */
399      return len;
400 }
401
402
403
404 static int
405 ber_len_uint64(const SmiUnsigned64 value)
406 {
407      SmiUnsigned64 val = value;
408      unsigned char ch;
409      int len = 0;
410      
411      do {
412           ch = (unsigned char) val;
413           val >>= 8;
414           len++;
415      } while ((val != 0) || (ch & 0x80) != 0x00);
416
417      len += ber_len_length(len);        /* length */
418      len += 1;                          /* tag */
419      return len;
420 }
421
422
423
424 static int
425 ber_len_val_oid(SmiType *smiType, len_type flags)
426 {
427     SmiSubid      oid[128];
428     unsigned int  oidlen = sizeof(oid)/sizeof(oid[0]);
429     int i;
430     
431     switch (flags) {
432     case len_max: 
433         oid[0] = 2;
434         for (i = 1; i < 128; i++) {
435             oid[i] = 4294967295UL;
436         }
437         break;
438     case len_mean:
439         /* see Aiko's measurements */
440         for (oidlen = 0; oidlen < 15; oidlen++) {
441             oid[oidlen] = 1;
442         }
443         break;
444     case len_min:
445         oid[0] = oid[1] = 0, oidlen = 2;
446         break;
447     }
448     return ber_len_oid(oid, oidlen);
449 }
450
451
452
453 static int
454 ber_len_val_octs(SmiType *smiType, len_type flags)
455 {
456     int len = 0;
457
458     SmiModule *smiModule;
459
460     smiModule = smiGetTypeModule(smiType);
461     if (smiModule && smiModule->name && smiType->name) {
462         int i;
463         for (i = 0; specialTypes[i].module; i++) {
464             if (strcmp(specialTypes[i].module, smiModule->name) == 0
465                 && (strcmp(specialTypes[i].name, smiType->name) == 0)) {
466                 break;
467             }
468         }
469         if (specialTypes[i].module) {
470             switch (flags) {
471             case len_max:
472                 return specialTypes[i].max;
473                 break;
474             case len_mean:
475                 return specialTypes[i].mean;
476                 break;
477             case len_min:
478                 return specialTypes[i].min;
479                 break;
480             }
481         }
482     }
483
484     switch (flags) {
485     case len_max:
486         len = smiGetMaxSize(smiType);
487         break;
488     case len_mean:
489         len = (smiGetMaxSize(smiType) + smiGetMinSize(smiType)) / 2;
490         break;
491     case len_min:
492         len = smiGetMinSize(smiType);
493         break;
494     }
495     return len;
496 }
497
498
499
500 static int
501 ber_len_val_bits(SmiType *smiType, len_type flags)
502 {
503     int len = 0;
504
505     switch (flags) {
506     case len_max:
507         len = smiGetMaxSize(smiType);
508         break;
509     case len_mean:
510         len = (smiGetMaxSize(smiType) + smiGetMinSize(smiType)) / 2;
511         break;
512     case len_min:
513         len = smiGetMinSize(smiType);
514         break;
515     }
516     return len;
517 }
518
519
520
521 static int
522 ber_len_val_enum(SmiType *smiType, len_type flags)
523 {
524      SmiInteger32 val = 0;
525
526      switch (flags) {
527      case len_max:
528          val = getAbsMaxEnum(smiType);
529          break;
530      case len_mean:
531          val = (getAbsMaxEnum(smiType) + getAbsMinEnum(smiType)) / 2;
532          break;
533      case len_min:
534          val = getAbsMinEnum(smiType);
535          break;
536      }
537      return ber_len_int32(val);
538 }
539
540
541
542 static int
543 ber_len_val_int32(SmiType *smiType, len_type flags)
544 {
545     SmiInteger32 val = 0;
546     
547     switch (flags) {
548     case len_max:
549         val = getAbsMaxInteger32(smiType);
550         break;
551     case len_mean:
552         val = (getAbsMaxInteger32(smiType) + getAbsMinInteger32(smiType)) / 2;
553         break;
554     case len_min:
555         val = getAbsMinInteger32(smiType);
556         break;       
557     }
558     return ber_len_int32(val);
559 }
560
561
562
563 static int
564 ber_len_val_uint32(SmiType *smiType, len_type flags)
565 {
566     SmiUnsigned32 val = 0;
567     
568     switch (flags) {
569     case len_max:
570         val = getMaxUnsigned32(smiType);
571         break;
572     case len_mean:
573         val = (getMaxUnsigned32(smiType) + getMinUnsigned32(smiType)) / 2;
574         break;
575     case len_min:
576         val = getMinUnsigned32(smiType);
577         break;
578     }
579     return ber_len_uint32(val);
580 }
581
582
583
584 static int
585 ber_len_val_int64(SmiType *smiType, len_type flags)
586 {
587     SmiInteger64 val = 0;
588
589     switch (flags) {
590     case len_max:
591         val = getAbsMaxInteger64(smiType);
592         break;
593     case len_mean:
594         val = (getAbsMaxInteger64(smiType) + getAbsMinInteger64(smiType)) / 2;
595         break;
596     case len_min:
597         val = getAbsMinInteger64(smiType);
598         break;
599     }
600     return ber_len_int64(val);
601 }
602
603
604
605 static int
606 ber_len_val_uint64(SmiType *smiType, len_type flags)
607 {
608     SmiUnsigned64 val = 0;
609
610     switch (flags) {
611     case len_max:
612         val = getMaxUnsigned64(smiType);
613         break;
614     case len_mean:
615         val = (getMaxUnsigned64(smiType) + getMinUnsigned64(smiType)) / 2;
616         break;
617     case len_min:
618         val = getMinUnsigned64(smiType);
619         break;
620     }
621     return ber_len_uint64(val);
622 }
623
624
625
626 static int
627 ber_len_val(SmiType *smiType, len_type flags)
628 {
629      int len = 0;
630      
631      switch (smiType->basetype) {
632      case SMI_BASETYPE_OBJECTIDENTIFIER:
633          len = ber_len_val_oid(smiType, flags);
634          break;
635      case SMI_BASETYPE_OCTETSTRING:
636          len = ber_len_val_octs(smiType, flags);
637          break;
638      case SMI_BASETYPE_BITS:
639          len = ber_len_val_bits(smiType, flags);
640          break;
641      case SMI_BASETYPE_ENUM:
642          len = ber_len_val_enum(smiType, flags);
643          break;
644      case SMI_BASETYPE_INTEGER32:
645          len = ber_len_val_int32(smiType, flags);
646          break;
647      case SMI_BASETYPE_UNSIGNED32:
648          len = ber_len_val_uint32(smiType, flags);
649          break;
650      case SMI_BASETYPE_INTEGER64:
651          len = ber_len_val_int64(smiType, flags);
652          break;
653      case SMI_BASETYPE_UNSIGNED64:
654          len = ber_len_val_uint64(smiType, flags);
655          break;
656      default:
657          break;
658      }
659
660      return len;
661 }
662
663
664
665 static void
666 append_index(SmiSubid *oid, unsigned int *oidlen,
667              SmiNode *indexNode, len_type flags)
668 {
669      SmiInteger32  int32 = 0;
670      SmiUnsigned32 uint32 = 0;
671      SmiType *indexType;
672      SmiModule *indexModule;
673      int i, len = 0;
674
675      if (! indexNode) return;
676
677      indexType = smiGetNodeType(indexNode);
678      if (! indexType) return;
679
680      indexModule = smiGetTypeModule(indexType);
681
682      switch (indexType->basetype) {
683      case SMI_BASETYPE_OBJECTIDENTIFIER:
684
685          switch (flags) {
686          case len_max:
687              len = 128 - *oidlen;
688              if (indexNode->implied) len--;
689              break;
690          case len_mean:
691              len = 16;
692              break;
693          case len_min:
694              len = 2;
695              break;
696          }
697          
698          if (! indexNode->implied && *oidlen < 128) {
699              oid[(*oidlen)++] = len;
700          }
701          for (i = 0; i < len && *oidlen < 128; i++) {
702              switch (flags) {
703              case len_max:
704                  if (i == 0) {
705                      oid[(*oidlen)++] = 2;
706                  } else {
707                      oid[(*oidlen)++] = 4294967295UL;
708                  }
709                  break;
710              case len_mean:
711                  oid[(*oidlen)++] = i + 1;
712                  break;
713              case len_min:
714                  oid[(*oidlen)++] = 0;
715                  break;
716              }
717          }
718          break;
719      case SMI_BASETYPE_OCTETSTRING:
720      case SMI_BASETYPE_BITS:
721          switch (flags) {
722          case len_max:
723              len = smiGetMaxSize(indexType);
724              break;
725          case len_mean:
726              len = (smiGetMaxSize(indexType) + smiGetMinSize(indexType) / 2);
727              break;
728          case len_min:
729              len = smiGetMinSize(indexType);
730              break;
731          }
732
733          if (indexModule && indexModule->name && indexType->name) {
734              int i;
735              for (i = 0; specialTypes[i].module; i++) {
736                  if (strcmp(specialTypes[i].module, indexModule->name) == 0
737                      && (strcmp(specialTypes[i].name, indexType->name) == 0)) {
738                      break;
739                  }
740              }
741              if (specialTypes[i].module) {
742                  switch (flags) {
743                  case len_max:
744                      len = specialTypes[i].max;
745                      break;
746                  case len_mean:
747                      len = specialTypes[i].mean;
748                      break;
749                  case len_min:
750                      len = specialTypes[i].min;
751                      break;
752                  }
753              }
754          }
755          
756          if (! indexNode->implied && *oidlen < 128) {
757              oid[(*oidlen)++] = len;
758          }
759          for (i = 0; i < len && *oidlen < 128; i++) {
760              switch (flags) {
761              case len_max:
762                  oid[(*oidlen)++] = 255;
763                  break;
764              case len_mean:
765                  if (i == 0) {
766                      oid[(*oidlen)++] = 1;
767                  } else {
768                      oid[(*oidlen)++] = (i%2) ? 85 : 170;
769                  }
770                  break;
771              case len_min:
772                  oid[(*oidlen)++] = 0;
773                  break;
774              }
775           }
776          break;
777      case SMI_BASETYPE_ENUM:
778          switch (flags) {
779          case len_max:
780              int32 = getAbsMaxEnum(indexType);
781              break;
782          case len_mean:
783              int32 = (getAbsMaxEnum(indexType) - getAbsMinEnum(indexType)) / 2;
784              break;
785          case len_min:
786              int32 = getAbsMinEnum(indexType);
787              break;
788          }
789          if (*oidlen < 128) {
790              oid[(*oidlen)++] = int32;
791          }
792          break;
793      case SMI_BASETYPE_INTEGER32:
794          switch (flags) {
795          case len_max:
796              int32 = getAbsMaxInteger32(indexType);
797              break;
798          case len_mean:
799              int32 = (getAbsMaxInteger32(indexType)
800                       + getAbsMinInteger32(indexType)) / 2;
801              break;
802          case len_min:
803              int32 = getAbsMinInteger32(indexType);
804              break;
805          }
806          if (*oidlen < 128) {
807              oid[(*oidlen)++] = int32;
808          }
809          break;
810      case SMI_BASETYPE_UNSIGNED32:
811          switch (flags) {
812          case len_max:
813              uint32 = getMaxUnsigned32(indexType);
814              break;
815          case len_mean:
816              uint32 = (getMaxUnsigned32(indexType)
817                        + getMinUnsigned32(indexType)) / 2;
818              break;
819          case len_min:
820              uint32 = getMinUnsigned32(indexType);
821              break;
822          }
823          if (*oidlen < 128) {
824              oid[(*oidlen)++] = uint32;
825          }
826          break;
827      case SMI_BASETYPE_UNKNOWN:
828      case SMI_BASETYPE_INTEGER64:
829      case SMI_BASETYPE_UNSIGNED64:
830      case SMI_BASETYPE_FLOAT32:
831      case SMI_BASETYPE_FLOAT64:
832      case SMI_BASETYPE_FLOAT128:
833      case SMI_BASETYPE_POINTER:
834          /* should never really get here */
835          break;
836      }
837 }
838
839 #undef DUMP_OID
840
841 static int
842 ber_len_varbind(SmiNode *smiNode, len_type flags)
843 {
844      SmiNode *row;
845      SmiSubid oid[128];
846      unsigned int oidlen = sizeof(oid)/sizeof(oid[0]);
847      int len = 0;
848 #ifdef DUMP_OID
849      int x;
850 #endif
851
852      switch (smiNode->nodekind) {
853      case SMI_NODEKIND_SCALAR:
854           for (oidlen = 0; oidlen < smiNode->oidlen; oidlen++) {
855                oid[oidlen] = smiNode->oid[oidlen];
856           }
857           oid[oidlen++] = 0;
858           break;
859      case SMI_NODEKIND_COLUMN:
860           for (oidlen = 0; oidlen < smiNode->oidlen; oidlen++) {
861                oid[oidlen] = smiNode->oid[oidlen];
862           }
863           row = smiGetParentNode(smiNode);
864           if (row) {
865                SmiNode *indexNode = NULL, *iNode;
866                SmiElement *smiElement;
867                
868                switch (row->indexkind) {
869                case SMI_INDEX_INDEX:
870                case SMI_INDEX_REORDER:
871                     indexNode = row;
872                     break;
873                case SMI_INDEX_EXPAND: /* TODO: we have to do more work here! */
874                     break;
875                case SMI_INDEX_AUGMENT:
876                case SMI_INDEX_SPARSE:
877                     indexNode = smiGetRelatedNode(row);
878                     break;
879                case SMI_INDEX_UNKNOWN:
880                     break;
881                }
882                if (indexNode) {
883                     for (smiElement = smiGetFirstElement(indexNode);
884                          smiElement;
885                          smiElement = smiGetNextElement(smiElement)) {
886                          iNode = smiGetElementNode(smiElement);
887                          append_index(oid, &oidlen, iNode, flags);
888                     }
889                }
890           }
891           break;
892      default:
893           return 0;
894      }
895
896 #ifdef DUMP_OID
897      fprintf(stderr, "%-32s\t", smiNode->name);
898      for (x = 0; x < oidlen; x++) {
899           fprintf(stderr, ".%u", oid[x]);
900      }
901      fprintf(stderr, "\n");
902 #endif
903
904      len += ber_len_oid(oid, oidlen);
905      len += ber_len_val(smiGetNodeType(smiNode), flags);
906      len += ber_len_length(len) + 1;
907
908      return len;
909 }
910
911
912
913 static int
914 isGroup(SmiNode *smiNode)
915 {
916     SmiNode *childNode;
917
918     if (smiNode->nodekind == SMI_NODEKIND_ROW) {
919         return 1;
920     }
921     
922     for (childNode = smiGetFirstChildNode(smiNode);
923          childNode;
924          childNode = smiGetNextChildNode(childNode)) {
925         if (childNode->nodekind == SMI_NODEKIND_SCALAR
926                 && childNode->access > SMI_ACCESS_NOTIFY) {
927             return 1;
928         }
929     }
930
931     return 0;
932 }
933
934
935
936 static void
937 dumpSizeOfPDU(FILE *f, SmiModule *smiModule, SmiNode *smiNode)
938 {
939      SmiNode *child;
940      int worst = 0;
941      int best = 0;
942      int avg = 0;
943      int b, w, a, n = 0;
944      
945      for (child = smiGetFirstChildNode(smiNode);
946           child;
947           child = smiGetNextChildNode(child)) {
948           if (child->access == SMI_ACCESS_READ_WRITE
949               || child->access == SMI_ACCESS_READ_ONLY) {
950
951                b = ber_len_varbind(child, len_min);
952                a = ber_len_varbind(child, len_mean);
953                w = ber_len_varbind(child, len_max);
954                
955                best += b, worst += w, avg += a, n++;
956           }
957      }
958
959      /* varbind list sequence length and tag */
960      best  += ber_len_length(best)  + 1;
961      avg   += ber_len_length(avg)   + 1;
962      worst += ber_len_length(worst) + 1;
963
964      /* request-id as defined in RFC 3416 */
965      best += ber_len_int32(0);
966      avg += ber_len_int32(1073741824);
967      worst += ber_len_int32(-214783648);
968      
969      /* error-status as defined in RFC 3416 */
970      best += ber_len_int32(0);
971      avg += ber_len_int32(0);
972      worst += ber_len_int32(18);
973      
974      /* error-index as defined in RFC 3416 */
975      best += ber_len_int32(0);
976      avg += ber_len_int32(0);
977      worst += ber_len_int32(n-1);
978
979      /* PDU sequence length and tag */
980      best  += ber_len_length(best)  + 1;
981      avg += ber_len_length(avg) + 1;
982      worst += ber_len_length(worst) + 1;
983      
984      fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n", smiModule->name, smiNode->name,
985              avg, best, worst);
986
987      if (detail) {
988          for (child = smiGetFirstChildNode(smiNode);
989               child;
990               child = smiGetNextChildNode(child)) {
991              if (child->access == SMI_ACCESS_READ_WRITE
992                  || child->access == SMI_ACCESS_READ_ONLY) {
993                  
994                  b = ber_len_varbind(child, len_min);
995                  a = ber_len_varbind(child, len_mean);
996                  w = ber_len_varbind(child, len_max);
997                  
998                  fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n",
999                          "", child->name, a, b, w);
1000              }
1001          }
1002      }
1003 }
1004
1005
1006
1007 static void
1008 dumpSizeOfCreatePDU(FILE *f, SmiModule *smiModule, SmiNode *smiNode,
1009                     int ignoreDefaultColumns)
1010 {
1011      SmiNode *child;
1012      SmiType *childType;
1013      SmiModule *childTypeModule;
1014      
1015      int worst = 0;
1016      int best = 0;
1017      int avg = 0;
1018      int b, w, a, n = 0;
1019      int isRowStatus;
1020      
1021      for (child = smiGetFirstChildNode(smiNode);
1022           child;
1023           child = smiGetNextChildNode(child)) {
1024           if (child->access == SMI_ACCESS_READ_WRITE) {
1025
1026                /* Ensure RowStatus columns are present even if they
1027                 * have a default value. */
1028
1029                childType = smiGetNodeType(child);
1030                childTypeModule = childType
1031                     ? smiGetTypeModule(childType) : NULL;
1032                
1033                isRowStatus
1034                     = (childType && childType->name
1035                        && childTypeModule && childTypeModule->name)
1036                     ? (strcmp(childType->name, "RowStatus") == 0
1037                        && strcmp(childTypeModule->name, "SNMPv2-TC") == 0)
1038                     : 0;
1039
1040                /* xxx at least one PDU must be present xxx */
1041
1042                if (ignoreDefaultColumns
1043                    && child->value.basetype != SMI_BASETYPE_UNKNOWN
1044                    && !isRowStatus) {
1045                     continue;
1046                }
1047
1048                b = ber_len_varbind(child, len_min);
1049                a = ber_len_varbind(child, len_mean);
1050                w = ber_len_varbind(child, len_max);
1051
1052 #if 0
1053                fprintf(f, "  %-32s\t[%d..%d] | %d\n", child->name, b, w, a);
1054 #endif
1055                
1056                best += b, worst += w, avg += a, n++;
1057           }
1058      }
1059
1060      /* varbind list sequence length and tag */
1061      best  += ber_len_length(best)  + 1;
1062      avg   += ber_len_length(avg)   + 1;
1063      worst += ber_len_length(worst) + 1;
1064
1065      /* request-id as defined in RFC 3416 */
1066      best += ber_len_int32(0);
1067      avg += ber_len_int32(1073741824);
1068      worst += ber_len_int32(-214783648);
1069      
1070      /* error-status as defined in RFC 3416 */
1071      best += ber_len_int32(0);
1072      avg += ber_len_int32(0);
1073      worst += ber_len_int32(18);
1074      
1075      /* error-index as defined in RFC 3416 */
1076      best += ber_len_int32(0);
1077      avg += ber_len_int32(0);
1078      worst += ber_len_int32(n-1);
1079
1080      /* PDU sequence length and tag */
1081      best  += ber_len_length(best)  + 1;
1082      avg += ber_len_length(avg) + 1;
1083      worst += ber_len_length(worst) + 1;
1084      
1085      fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n", smiModule->name, smiNode->name,
1086              avg, best, worst);
1087 }
1088
1089
1090
1091 static void
1092 dumpSizeOfNotificationPDU(FILE *f, SmiModule *smiModule, SmiNode *smiNode)
1093 {
1094      SmiElement *smiElement;
1095      SmiNode *varNode;
1096      int worst = 0;
1097      int best = 0;
1098      int avg = 0;
1099      int w, b, a;
1100      int len = 0;
1101      static const SmiSubid snmpTrapOid0[]
1102           = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
1103      static const int snmpTrapOid0Len
1104           = sizeof(snmpTrapOid0) / sizeof(SmiSubid);
1105      
1106      b = 15, w = 19, a = 18;
1107      best += b, worst += w, avg += a;
1108      
1109      len += ber_len_oid(smiNode->oid, smiNode->oidlen);
1110      len += ber_len_oid(snmpTrapOid0, snmpTrapOid0Len);
1111      len += ber_len_length(len) + 1;
1112      b = len, w = len, a = len;
1113      best += b, worst += w, avg += a;
1114      
1115      for (smiElement = smiGetFirstElement(smiNode);
1116           smiElement;
1117           smiElement = smiGetNextElement(smiElement)) {
1118           varNode = smiGetElementNode(smiElement);
1119           if (! varNode) continue;
1120
1121           b = ber_len_varbind(varNode, len_min);
1122           a = ber_len_varbind(varNode, len_mean);
1123           w = ber_len_varbind(varNode, len_max);
1124           
1125           best += b, worst += w, avg += a;
1126      }
1127
1128      /* varbind list sequence length and tag */
1129      best  += ber_len_length(best)  + 1;
1130      avg   += ber_len_length(avg)   + 1;
1131      worst += ber_len_length(worst) + 1;
1132      
1133      /* request-id as defined in RFC 3416 */
1134      best += ber_len_int32(0);
1135      avg += ber_len_int32(1073741824);
1136      worst += ber_len_int32(-214783648);
1137      
1138      /* error-status as defined in RFC 3416 */
1139      best += ber_len_int32(0);
1140      avg += ber_len_int32(0);
1141      worst += ber_len_int32(18);
1142      
1143      /* error-index as defined in RFC 3416 */
1144      best += ber_len_int32(0);
1145      avg += ber_len_int32(0);
1146      worst += ber_len_int32(0);
1147
1148      /* PDU sequence length and tag */
1149      best  += ber_len_length(best)  + 1;
1150      avg += ber_len_length(avg) + 1;
1151      worst += ber_len_length(worst) + 1;
1152      
1153      fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n", smiModule->name, smiNode->name,
1154              avg, best, worst);
1155
1156      if (detail) {
1157          b = 15, w = 19, a = 18;
1158          fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n",
1159                  "", "sysUpTime", a, b, w);
1160          
1161          len = 0;
1162          len += ber_len_oid(smiNode->oid, smiNode->oidlen);
1163          len += ber_len_oid(snmpTrapOid0, snmpTrapOid0Len);
1164          len += ber_len_length(len) + 1;
1165          b = len, w = len, a = len;
1166          fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n",
1167                  "", "snmpTrapOID", a, b, w);
1168          
1169          for (smiElement = smiGetFirstElement(smiNode);
1170               smiElement;
1171               smiElement = smiGetNextElement(smiElement)) {
1172              varNode = smiGetElementNode(smiElement);
1173              if (! varNode) continue;
1174              
1175              b = ber_len_varbind(varNode, len_min);
1176              a = ber_len_varbind(varNode, len_mean);
1177              w = ber_len_varbind(varNode, len_max);
1178              
1179              fprintf(f, "%-23s %-23s \t%d\t[%d..%d]\n",
1180                      "", varNode->name, a, b, w);
1181          }
1182      }
1183 }
1184
1185
1186
1187 static void
1188 dumpGroupPduSizes(FILE *f, SmiModule *smiModule)
1189 {
1190     SmiNode *smiNode;
1191
1192     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ANY);
1193          smiNode;
1194          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ANY)) {
1195         if (isGroup(smiNode)) {
1196             dumpSizeOfPDU(f, smiModule, smiNode);
1197         }
1198     }
1199 }
1200
1201
1202
1203 static void
1204 dumpFullRowCreatePduSizes(FILE *f, SmiModule *smiModule)
1205 {
1206     SmiNode *smiNode;
1207     
1208     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ROW);
1209          smiNode;
1210          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ROW)) {
1211         if (smiNode->create) {
1212             dumpSizeOfCreatePDU(f, smiModule, smiNode, 0);
1213         }
1214     }
1215 }
1216
1217      
1218
1219 static void
1220 dumpSmallRowCreatePduSizes(FILE *f, SmiModule *smiModule)
1221 {
1222     SmiNode *smiNode;
1223     
1224     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_ROW);
1225          smiNode;
1226          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_ROW)) {
1227         if (smiNode->create) {
1228             dumpSizeOfCreatePDU(f, smiModule, smiNode, 1);
1229         }
1230     }
1231 }
1232
1233
1234
1235 static void
1236 dumpNotificationPduSizes(FILE *f, SmiModule *smiModule)
1237 {
1238     SmiNode *smiNode;
1239     
1240     for (smiNode = smiGetFirstNode(smiModule, SMI_NODEKIND_NOTIFICATION);
1241          smiNode;
1242          smiNode = smiGetNextNode(smiNode, SMI_NODEKIND_NOTIFICATION)) {
1243         dumpSizeOfNotificationPDU(f, smiModule, smiNode);
1244     }
1245 }
1246
1247
1248
1249 static void
1250 dumpSizes(int modc, SmiModule **modv, int flags, char *output)
1251 {
1252      int       i;
1253      FILE      *f = stdout;
1254      
1255      silent = (flags & SMIDUMP_FLAG_SILENT);
1256      
1257      if (output) {
1258           f = fopen(output, "w");
1259           if (!f) {
1260                fprintf(stderr, "smidump: cannot open %s for writing: ", output);
1261                perror(NULL);
1262                exit(1);
1263           }
1264      }
1265      
1266      if (flags & SMIDUMP_FLAG_UNITE) {
1267           if (! silent) {
1268                int pos = 8888;
1269                fprintf(f, "# united module PDU sizes (generated by smidump "
1270                        SMI_VERSION_STRING ")\n");
1271                fprintf(f, "#\n# smidump -u -f sizes");
1272                for (i = 0; i < modc; i++) {
1273                     int len = strlen(modv[i]->name);
1274                     if (pos + len > 70) {
1275                          fprintf(f, " \\\n#\t"), pos = 8;
1276                     }
1277                     fprintf(f, "%s ", modv[i]->name);
1278                     pos += len + 1;
1279                }
1280                fprintf(f, "%s\n", (pos == 8) ? "" : "\n");
1281           }
1282           fprintf(f, "\n# size of PDUs for groups and rows:\n\n");
1283           for (i = 0; i < modc; i++) {
1284               dumpGroupPduSizes(f, modv[i]);
1285           }
1286           fprintf(f, "\n# size of one-shot row creation PDUs including columns with default values:\n\n");
1287           for (i = 0; i < modc; i++) {
1288               dumpFullRowCreatePduSizes(f, modv[i]);
1289           }
1290           fprintf(f, "\n# size of one-shot row creation PDUs excluding columns with default values:\n\n");
1291           for (i = 0; i < modc; i++) {
1292               dumpSmallRowCreatePduSizes(f, modv[i]);
1293           }
1294           fprintf(f, "\n# size of notification PDUs:\n\n");
1295           for (i = 0; i < modc; i++) {
1296               dumpNotificationPduSizes(f, modv[i]);
1297           }
1298      } else {
1299           for (i = 0; i < modc; i++) {
1300                if (! silent) {
1301                     fprintf(f, "# %s module PDU sizes (generated by smidump "
1302                             SMI_VERSION_STRING ")\n\n", modv[i]->name);
1303                }
1304                fprintf(f, "\n# size of PDUs for groups and rows:\n\n");
1305                dumpGroupPduSizes(f, modv[i]);
1306                fprintf(f, "\n# size of one-shot row creation PDUs including columns with default values:\n\n");
1307                dumpFullRowCreatePduSizes(f, modv[i]);
1308                fprintf(f, "\n# size of one-shot row creation PDUs excluding columns with default values:\n\n");
1309                dumpSmallRowCreatePduSizes(f, modv[i]);
1310                fprintf(f, "\n# size of notification PDUs:\n\n");
1311                dumpNotificationPduSizes(f, modv[i]);
1312           }
1313      }
1314      
1315      if (fflush(f) || ferror(f)) {
1316           perror("smidump: write error");
1317           exit(1);
1318      }
1319      
1320      if (output) {
1321           fclose(f);
1322      }
1323 }
1324
1325 void
1326 initSizes()
1327 {
1328     static SmidumpDriverOption opt[] = {
1329         { "variables", OPT_FLAG, &detail, 0,
1330           "show detailed information the sizes of variables"},
1331         { 0, OPT_END, 0, 0 }
1332     };
1333     
1334     static SmidumpDriver driver = {
1335         "sizes",
1336         dumpSizes,
1337         SMI_FLAG_NODESCR,
1338         0,
1339         "RFC 3416 PDU sizes excluding message / transport headers",
1340         opt,
1341         NULL
1342     };
1343     
1344     smidumpRegisterDriver(&driver);
1345 }