/* * check.c -- * * This module contains semantics checks that are shared between * the SMI parser backends. * * Copyright (c) 2000 Frank Strauss, Technical University of Braunschweig. * * See the file "COPYING" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * @(#) $Id: check.c 7640 2008-01-31 15:29:52Z schoenw $ */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_WIN_H #include "win.h" #endif #include "error.h" #include "util.h" #include "data.h" #include "check.h" #include "smi.h" #ifdef HAVE_DMALLOC_H #include #endif /* *---------------------------------------------------------------------- * * compareValues -- * * Compare two SmiValues a and b. * * Results: * <= -2 if a is less than b-1 * -1 if a is b-1 * 0 if equal * 1 if a is b+1 * >= 2 if a is greater than b+1 * * Side effects: * None. * *---------------------------------------------------------------------- */ static int compareValues(SmiValue *a, SmiValue *b) { if ((a->basetype == SMI_BASETYPE_UNSIGNED32) && (b->basetype == SMI_BASETYPE_UNSIGNED32)) { if (a->value.unsigned32 == b->value.unsigned32) { return 0; } else { if (a->value.unsigned32 > b->value.unsigned32) { if (a->value.unsigned32 == b->value.unsigned32 + 1) { return 1; } else { return 2; } } else if (a->value.unsigned32 < b->value.unsigned32) { if (a->value.unsigned32 + 1 == b->value.unsigned32) { return -1; } else { return -2; } } } } if ((a->basetype == SMI_BASETYPE_INTEGER32) && (b->basetype == SMI_BASETYPE_INTEGER32)) { if (a->value.integer32 == b->value.integer32) { return 0; } else { if (a->value.integer32 > b->value.integer32) { if (a->value.integer32 == b->value.integer32 + 1) { return 1; } else { return 2; } } else if (a->value.integer32 < b->value.integer32) { if (a->value.integer32 + 1 == b->value.integer32) { return -1; } else { return -2; } } } } if ((a->basetype == SMI_BASETYPE_UNSIGNED32) && (b->basetype == SMI_BASETYPE_INTEGER32)) { if ((b->value.integer32 < -1) || ((a->value.unsigned32 > 1) && (a->value.unsigned32-1 > 2147483647))) { return 2; } return a->value.unsigned32 - b->value.integer32; } if ((a->basetype == SMI_BASETYPE_INTEGER32) && (b->basetype == SMI_BASETYPE_UNSIGNED32)) { if ((a->value.integer32 < -1) || ((b->value.unsigned32 > 1) && (b->value.unsigned32-1 > 2147483647))) { return -2; } return b->value.unsigned32 - a->value.integer32; } return 0; } /* *---------------------------------------------------------------------- * * redefinition -- * * Print out error messages about a (case) redefinition. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void redefinition(Parser *parser, int line1, char *name1, Module *module, int line2, char *name2) { char *tmp = parser->path; int equal = (strcmp(name1, name2) == 0); if (!strcmp(name1, "IpAddress") || !strcmp(name1, "TimeTicks") || !strcmp(name1, "Opaque") || !strcmp(name1, "Integer32") || !strcmp(name1, "Unsigned32") || !strcmp(name1, "Counter32") || !strcmp(name1, "Gauge32") || !strcmp(name1, "Counter64") || !strcmp(name1, "Integer64") || !strcmp(name1, "Unsigned64")) { if (line1) { smiPrintErrorAtLine(parser, ERR_BASETYPE_REDEFINITION, line1, name1); } else { smiPrintError(parser, ERR_BASETYPE_REDEFINITION, name1); } } else { if (! module) { if (equal) { if (line1) { smiPrintErrorAtLine(parser, ERR_REDEFINITION, line1, name1); } else { smiPrintError(parser, ERR_REDEFINITION, name1); } } else { if (line1) { smiPrintErrorAtLine(parser, ERR_CASE_REDEFINITION, line1, name1, name2); } else { smiPrintError(parser, ERR_CASE_REDEFINITION, name1, name2); } } } else { if (equal) { if (line1) { smiPrintErrorAtLine(parser, ERR_EXT_REDEFINITION, line1, module->export.name, name1); } else { smiPrintError(parser, ERR_EXT_REDEFINITION, module->export.name, name1); } } else { if (line1) { smiPrintErrorAtLine(parser, ERR_EXT_CASE_REDEFINITION, line1, name1, module->export.name, name2); } else { smiPrintError(parser, ERR_EXT_CASE_REDEFINITION, name1, module->export.name, name2); } } parser->path = module->export.path; } smiPrintErrorAtLine(parser, ERR_PREVIOUS_DEFINITION, line2, name2); if (module) { parser->path = tmp; } } } /* *---------------------------------------------------------------------- * * smiCheckObjectName -- * * Check whether a given object name already exists * in a given module. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckObjectName(Parser *parser, Module *module, char *name) { Object *objectPtr; Type *typePtr; Module *modPtr; int errRedef = smiGetErrorSeverity(ERR_REDEFINITION); int errExtRedef = smiGetErrorSeverity(ERR_EXT_REDEFINITION); int errCaseRedef = smiGetErrorSeverity(ERR_CASE_REDEFINITION); int errExtCaseRedef = smiGetErrorSeverity(ERR_EXT_CASE_REDEFINITION); if (! (parser->flags & SMI_FLAG_ERRORS) || (errRedef > smiHandle->errorLevel && errExtRedef > smiHandle->errorLevel && errCaseRedef > smiHandle->errorLevel && errExtCaseRedef > smiHandle->errorLevel)) { return; } /* * This would really benefit from having a hash table... */ for (modPtr = smiHandle->firstModulePtr; modPtr; modPtr = modPtr->nextPtr) { /* * Skip all external modules if we are not interested in * generating warning on extern redefinitions. */ if (errExtRedef > smiHandle->errorLevel && errExtCaseRedef > smiHandle->errorLevel && modPtr != module) { continue; } for (objectPtr = modPtr->firstObjectPtr; objectPtr; objectPtr = objectPtr->nextPtr) { if (! (objectPtr->flags & FLAG_INCOMPLETE) && ! strcasecmp(name, objectPtr->export.name)) { redefinition(parser, 0, name, modPtr == module ? NULL : objectPtr->modulePtr, objectPtr->line, objectPtr->export.name); } } for (typePtr = modPtr->firstTypePtr; typePtr; typePtr = typePtr->nextPtr) { /* TODO: must ignore SEQUENCE types here ... */ if (! (typePtr->flags & FLAG_INCOMPLETE) && typePtr->export.name && !strcasecmp(name, typePtr->export.name)) { redefinition(parser, 0, name, modPtr == module ? NULL : typePtr->modulePtr, typePtr->line, typePtr->export.name); } } } } /* *---------------------------------------------------------------------- * * smiCheckTypeName -- * * Check whether a given type name already exists * in a given module. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckTypeName(Parser *parser, Module *module, char *name, int line) { Object *objectPtr; Type *typePtr; Module *modPtr; int errRedef = smiGetErrorSeverity(ERR_REDEFINITION); int errExtRedef = smiGetErrorSeverity(ERR_EXT_REDEFINITION); int errCaseRedef = smiGetErrorSeverity(ERR_CASE_REDEFINITION); int errExtCaseRedef = smiGetErrorSeverity(ERR_EXT_CASE_REDEFINITION); if (! (parser->flags & SMI_FLAG_ERRORS) || (errRedef > smiHandle->errorLevel && errExtRedef > smiHandle->errorLevel && errCaseRedef > smiHandle->errorLevel && errExtCaseRedef > smiHandle->errorLevel)) { return; } /* * This would really benefit from having a hash table... */ for (modPtr = smiHandle->firstModulePtr; modPtr; modPtr = modPtr->nextPtr) { /* * Skip all external modules if we are not interested in * generating warning on extern redefinitions. */ if (errExtRedef > smiHandle->errorLevel && errExtCaseRedef > smiHandle->errorLevel && modPtr != module) { continue; } for (typePtr = modPtr->firstTypePtr; typePtr; typePtr = typePtr->nextPtr) { /* TODO: must ignore SEQUENCE types here ... */ if (! (typePtr->flags & FLAG_INCOMPLETE) && typePtr->export.name && !strcasecmp(name, typePtr->export.name)) { redefinition(parser, line, name, modPtr == module ? NULL : typePtr->modulePtr, typePtr->line, typePtr->export.name); } } for (objectPtr = modPtr->firstObjectPtr; objectPtr; objectPtr = objectPtr->nextPtr) { if (! (objectPtr->flags & FLAG_INCOMPLETE) && ! strcasecmp(name, objectPtr->export.name)) { redefinition(parser, line, name, modPtr == module ? NULL : objectPtr->modulePtr, objectPtr->line, objectPtr->export.name); } } } } /* *---------------------------------------------------------------------- * * smiCheckFormat -- * * Check whether a format specification is valid. * * Results: * Returns 1 of the format is acceptable and 0 otherwise. * * Side effects: * None. * *---------------------------------------------------------------------- */ int smiCheckFormat(Parser *parser, SmiBasetype basetype, char *format, int line) { int n, repeat, error = 1; char *p = format; switch (basetype) { case SMI_BASETYPE_INTEGER32: case SMI_BASETYPE_INTEGER64: case SMI_BASETYPE_UNSIGNED32: case SMI_BASETYPE_UNSIGNED64: if (*p == 'x' || *p == 'o' || *p == 'b') { p++; error = (*p != 0); } else if (*p == 'd') { p++; if (! *p) { error = 0; break; } if (*p != '-') { error = 0; break; } for (n = 0, p++; *p && isdigit((int) *p); p++, n++) ; error = (*p != 0 || n <= 0); } break; case SMI_BASETYPE_OCTETSTRING: while (*p) { if ((repeat = (*p == '*'))) p++; /* part 1 */ for (n = 0; *p && isdigit((int) *p); p++, n++) ;/* part 2 */ if (! *p || n == 0) { break; } if (*p != 'x' && *p != 'd' && *p != 'o' /* part 3 */ && *p != 'a' && *p != 't') { break; } p++; if (*p /* part 4 */ && ! isdigit((int) *p) && *p != '*') p++; if (repeat && *p /* part 5 */ && ! isdigit((int) *p) && *p != '*') p++; } error = *p; break; default: break; } if (error) { if (line) { smiPrintErrorAtLine(parser, ERR_INVALID_FORMAT, line, format); } else { smiPrintError(parser, ERR_INVALID_FORMAT, format); } } return ! error; } /* *---------------------------------------------------------------------- * * smiCheckNamedNumberRedefinition -- * * Check whether named numbers redefine names or numbers. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckNamedNumberRedefinition(Parser *parser, Type *type) { List *list1Ptr, *list2Ptr; NamedNumber *nn1Ptr, *nn2Ptr; if (! type || (type->export.basetype != SMI_BASETYPE_ENUM && type->export.basetype != SMI_BASETYPE_BITS)) { return; } for (list1Ptr = type->listPtr; list1Ptr; list1Ptr = list1Ptr->nextPtr) { nn1Ptr = (NamedNumber *)(list1Ptr->ptr); for (list2Ptr = list1Ptr->nextPtr; list2Ptr; list2Ptr = list2Ptr->nextPtr) { nn2Ptr = (NamedNumber *)(list2Ptr->ptr); if (type->export.basetype == SMI_BASETYPE_ENUM) { if (!strcmp(nn1Ptr->export.name, nn2Ptr->export.name)) { smiPrintErrorAtLine(parser, ERR_ENUM_NAME_REDEFINITION, type->line, nn1Ptr->export.name); } if (nn1Ptr->export.value.value.integer32 == nn2Ptr->export.value.value.integer32) { smiPrintErrorAtLine(parser, ERR_ENUM_NUMBER_REDEFINITION, type->line, nn1Ptr->export.value.value.integer32); } } if (type->export.basetype == SMI_BASETYPE_BITS) { if (!strcmp(nn1Ptr->export.name, nn2Ptr->export.name)) { smiPrintErrorAtLine(parser, ERR_BITS_NAME_REDEFINITION, type->line, nn1Ptr->export.name); } if (nn1Ptr->export.value.value.unsigned32 == nn2Ptr->export.value.value.unsigned32) { smiPrintErrorAtLine(parser, ERR_BITS_NUMBER_REDEFINITION, type->line, nn1Ptr->export.value.value.unsigned32); } } } } } /* *---------------------------------------------------------------------- * * smiCheckNamedNumberSubtyping -- * * Check whether named numbers in a derived type are compatible * with the named numbers in the parent type. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckNamedNumberSubtyping(Parser *parser, Type *type) { List *list1Ptr, *list2Ptr; NamedNumber *nn1Ptr, *nn2Ptr; if (! type || ! type->parentPtr || ! type->parentPtr->parentPtr || (type->export.basetype != SMI_BASETYPE_ENUM && type->export.basetype != SMI_BASETYPE_BITS)) { return; } for (list1Ptr = type->listPtr; list1Ptr; list1Ptr = list1Ptr->nextPtr) { nn1Ptr = (NamedNumber *)(list1Ptr->ptr); for (list2Ptr = type->parentPtr->listPtr; list2Ptr; list2Ptr = list2Ptr->nextPtr) { nn2Ptr = (NamedNumber *)(list2Ptr->ptr); if (type->export.basetype == SMI_BASETYPE_ENUM) { if (! strcmp(nn1Ptr->export.name, nn2Ptr->export.name) && nn1Ptr->export.value.value.integer32 == nn2Ptr->export.value.value.integer32) { break; } } if (type->export.basetype == SMI_BASETYPE_BITS) { if (! strcmp(nn1Ptr->export.name, nn2Ptr->export.name) && nn1Ptr->export.value.value.unsigned32 == nn2Ptr->export.value.value.unsigned32) { break; } } } if (! list2Ptr) { if (type->export.basetype == SMI_BASETYPE_ENUM) { if (type->parentPtr->export.name) { smiPrintErrorAtLine(parser, ERR_ENUM_SUBTYPE_OF, type->line, nn1Ptr->export.name, nn1Ptr->export.value.value.integer32, type->parentPtr->export.name); } else { smiPrintErrorAtLine(parser, ERR_ENUM_SUBTYPE, type->line, nn1Ptr->export.name, nn1Ptr->export.value.value.integer32); } } if (type->export.basetype == SMI_BASETYPE_BITS) { if (type->parentPtr->export.name) { smiPrintErrorAtLine(parser, ERR_BITS_SUBTYPE_OF, type->line, nn1Ptr->export.name, type->parentPtr->export.name); } else { smiPrintErrorAtLine(parser, ERR_BITS_SUBTYPE, type->line, nn1Ptr->export.name); } } } } } /* *---------------------------------------------------------------------- * * smiCheckNamedNumbersOrder -- * * Check and normalize the order of named numbers in a bits * or enumeration type. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckNamedNumbersOrder(Parser *parser, Type *type) { List *listPtr, *lastPtr, *nextPtr, *ptr; NamedNumber *nnPtr; int shutup = 0; if (! type || ! type->parentPtr || (type->export.basetype != SMI_BASETYPE_ENUM && type->export.basetype != SMI_BASETYPE_BITS)) { return; } /* Check whether the first bit has been given a name. */ if (type->export.basetype == SMI_BASETYPE_BITS) { for (listPtr = type->listPtr; listPtr; listPtr = listPtr->nextPtr) { nnPtr = (NamedNumber *)(listPtr->ptr); if (nnPtr->export.value.value.unsigned32 == 0) break; } if (! listPtr) { smiPrintErrorAtLine(parser, ERR_BITS_ZERO_NOT_NAMED, type->line); } } lastPtr = NULL; for (listPtr = type->listPtr; listPtr; listPtr = nextPtr) { nextPtr = listPtr->nextPtr; nnPtr = (NamedNumber *)(listPtr->ptr); if (lastPtr) { if ((type->export.basetype == SMI_BASETYPE_ENUM) && (((NamedNumber *)(listPtr->ptr))->export.value.value.integer32 <= ((NamedNumber *)(lastPtr->ptr))->export.value.value.integer32)) { if (!shutup) { smiPrintErrorAtLine(parser, ERR_NAMED_NUMBERS_NOT_ASCENDING, type->line, type->export.name); shutup = 1; } /* remove listPtr from the list */ lastPtr->nextPtr = listPtr->nextPtr; /* re-insert listPtr at the right position */ if (((NamedNumber *)(type->listPtr->ptr))->export.value.value.integer32 > ((NamedNumber *)(listPtr->ptr))->export.value.value.integer32) { listPtr->nextPtr = type->listPtr; type->listPtr = listPtr; } else { for (ptr = type->listPtr; ptr; ptr = ptr->nextPtr) { if ((!ptr->nextPtr) || (((NamedNumber *)(ptr->nextPtr->ptr))->export.value.value.integer32 >= ((NamedNumber *)(listPtr->ptr))->export.value.value.integer32)) { listPtr->nextPtr = ptr->nextPtr; ptr->nextPtr = listPtr; break; } } } /* set lastPtr to the last processed item */ for (lastPtr = listPtr; lastPtr->nextPtr != nextPtr; lastPtr = lastPtr->nextPtr); continue; } if ((type->export.basetype == SMI_BASETYPE_BITS) && (((NamedNumber *)(listPtr->ptr))->export.value.value.unsigned32 <= ((NamedNumber *)(lastPtr->ptr))->export.value.value.unsigned32)) { if (!shutup) { smiPrintErrorAtLine(parser, ERR_NAMED_NUMBERS_NOT_ASCENDING, type->line, type->export.name); shutup = 1; } /* remove listPtr from the list */ lastPtr->nextPtr = listPtr->nextPtr; /* re-insert listPtr at the right position */ if (((NamedNumber *)(type->listPtr->ptr))->export.value.value.unsigned32 > ((NamedNumber *)(listPtr->ptr))->export.value.value.unsigned32) { listPtr->nextPtr = type->listPtr; type->listPtr = listPtr; } else { for (ptr = type->listPtr; ptr; ptr = ptr->nextPtr) { if ((!ptr->nextPtr) || (((NamedNumber *)(ptr->nextPtr->ptr))->export.value.value.unsigned32 > ((NamedNumber *)(listPtr->ptr))->export.value.value.unsigned32)) { listPtr->nextPtr = ptr->nextPtr; ptr->nextPtr = listPtr; break; } } } /* set lastPtr to the last processed item */ for (lastPtr = listPtr; lastPtr->nextPtr != nextPtr; lastPtr = lastPtr->nextPtr); continue; } } lastPtr = listPtr; } } /* *---------------------------------------------------------------------- * * smiCheckIndex -- * * Check whether an index conforms to the SMI restrictions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckIndex(Parser *parser, Object *object) { List *listPtr, *list2Ptr; Object *indexPtr; Type *typePtr, *rTypePtr; Range *rangePtr; NamedNumber *nnPtr; Node *nodePtr; int minSize, maxSize, len = 0; int aux = 0, cols = 0, acc = 0; for (nodePtr = object->nodePtr->firstChildPtr, cols = 0; nodePtr; nodePtr = nodePtr->nextPtr) { cols++; } for (listPtr = object->listPtr; listPtr; listPtr = listPtr->nextPtr) { indexPtr = (Object *) listPtr->ptr; typePtr = indexPtr->typePtr; /* checkObjects() already handles unknown objects */ if (indexPtr->export.nodekind != SMI_NODEKIND_COLUMN && ((indexPtr->flags & FLAG_INCOMPLETE) == 0)) { smiPrintErrorAtLine(parser, ERR_INDEX_NOT_COLUMN, indexPtr->line, indexPtr->export.name, object->export.name); } if (!typePtr) continue; switch (typePtr->export.basetype) { case SMI_BASETYPE_INTEGER32: for (rTypePtr = typePtr; rTypePtr && ! rTypePtr->listPtr; rTypePtr = rTypePtr->parentPtr) { } if (! rTypePtr) { if (object->modulePtr != indexPtr->modulePtr) { smiPrintErrorAtLine(parser, ERR_INDEX_NO_RANGE_MOD, object->line, indexPtr->modulePtr->export.name, indexPtr->export.name, object->export.name); } else { smiPrintErrorAtLine(parser, ERR_INDEX_NO_RANGE, indexPtr->line, indexPtr->export.name, object->export.name); } } else { for (list2Ptr = rTypePtr->listPtr; list2Ptr; list2Ptr = list2Ptr->nextPtr) { rangePtr = (Range *) list2Ptr->ptr; if (rangePtr->export.maxValue.value.integer32 < 0) { smiPrintErrorAtLine(parser, ERR_INDEX_RANGE_NEGATIVE, indexPtr->line, indexPtr->export.name, object->export.name); break; } } } len++; break; case SMI_BASETYPE_OCTETSTRING: /* TODO: We need to check ranges of parent types as well if this type does not have a range restriction. */ for (rTypePtr = typePtr; rTypePtr && ! rTypePtr->listPtr; rTypePtr = rTypePtr->parentPtr) { } minSize = 65535; maxSize = -1; if (! rTypePtr) { if (object->modulePtr != indexPtr->modulePtr) { smiPrintErrorAtLine(parser, ERR_INDEX_STRING_NO_SIZE_MOD, object->line, indexPtr->modulePtr->export.name, indexPtr->export.name, object->export.name); } else { smiPrintErrorAtLine(parser, ERR_INDEX_STRING_NO_SIZE, indexPtr->line, indexPtr->export.name, object->export.name); } minSize = 0; maxSize = 65535; } else { for (list2Ptr = rTypePtr->listPtr; list2Ptr; list2Ptr = list2Ptr->nextPtr) { rangePtr = (Range *) list2Ptr->ptr; if (rangePtr->export.minValue.value.integer32 < minSize) { minSize = rangePtr->export.minValue.value.integer32; } if (rangePtr->export.maxValue.value.integer32 > maxSize) { maxSize = rangePtr->export.maxValue.value.integer32; } } if (minSize == 65535) { minSize = 0; } if (maxSize < 0) { maxSize = 65535; } } len += maxSize; if (minSize != maxSize) { if (! (object->export.implied && (! listPtr->nextPtr))) { len++; } } break; case SMI_BASETYPE_OBJECTIDENTIFIER: if (object->modulePtr != indexPtr->modulePtr) { smiPrintErrorAtLine(parser, ERR_INDEX_OID_NO_SIZE_MOD, object->line, indexPtr->modulePtr->export.name, indexPtr->export.name, object->export.name); } else { smiPrintErrorAtLine(parser, ERR_INDEX_OID_NO_SIZE, indexPtr->line, indexPtr->export.name, object->export.name); } len += 128; if (!indexPtr->export.implied) { len++; } break; case SMI_BASETYPE_UNSIGNED32: len++; break; case SMI_BASETYPE_INTEGER64: case SMI_BASETYPE_UNSIGNED64: case SMI_BASETYPE_FLOAT32: case SMI_BASETYPE_FLOAT64: case SMI_BASETYPE_FLOAT128: case SMI_BASETYPE_UNKNOWN: smiPrintErrorAtLine(parser, ERR_INDEX_BASETYPE, object->line, typePtr->export.name ? typePtr->export.name : "[unknown]", indexPtr->export.name, object->export.name); break; case SMI_BASETYPE_BITS: /* TODO: BITS are somehow treated as octet strings - but what is the max len? */ break; case SMI_BASETYPE_ENUM: for (list2Ptr = typePtr->listPtr; list2Ptr; list2Ptr = list2Ptr->nextPtr) { nnPtr = (NamedNumber *)(list2Ptr->ptr); if (nnPtr->export.value.value.integer32 < 0) { smiPrintErrorAtLine(parser, ERR_INDEX_ENUM_NEGATIVE, indexPtr->line, indexPtr->export.name, object->export.name); break; } } len++; break; } if (indexPtr->export.value.basetype != SMI_BASETYPE_UNKNOWN) { smiPrintErrorAtLine(parser, ERR_INDEX_DEFVAL, indexPtr->line, indexPtr->export.name, object->export.name); } for (nodePtr = object->nodePtr->firstChildPtr; nodePtr; nodePtr = nodePtr->nextPtr) { if (indexPtr == nodePtr->lastObjectPtr) { aux++; break; } } } if (object->export.oidlen + 1 + len > 128) { smiPrintErrorAtLine(parser, ERR_INDEX_TOO_LARGE, object->line, object->export.name, (object->export.oidlen + 1 + len) - 128); } /* RFC 2578 section 7.7: Auxiliary objects must be not-accessible except in some interesting corner cases. */ for (listPtr = object->listPtr; listPtr; listPtr = listPtr->nextPtr) { indexPtr = (Object *) listPtr->ptr; typePtr = indexPtr->typePtr; if (aux < cols) { if ((parser->modulePtr->export.language == SMI_LANGUAGE_SMIV2) && (indexPtr->nodePtr->parentPtr == object->nodePtr)) { if (indexPtr->export.access != SMI_ACCESS_NOT_ACCESSIBLE) { smiPrintErrorAtLine(parser, ERR_INDEX_ACCESSIBLE, object->line, indexPtr->export.name, object->export.name); } } } for (nodePtr = object->nodePtr->firstChildPtr, acc = 0; nodePtr; nodePtr = nodePtr->nextPtr) { if (indexPtr == nodePtr->lastObjectPtr && indexPtr->export.access != SMI_ACCESS_NOT_ACCESSIBLE) { acc++; } } } if ((parser->modulePtr->export.language == SMI_LANGUAGE_SMIV2) && aux == cols && acc != 1) { smiPrintErrorAtLine(parser, ERR_INDEX_NON_ACCESSIBLE, object->line, object->export.name); } } /* *---------------------------------------------------------------------- * * smiCheckAugment -- * * Check whether a table augmentation conforms to the SMI * restrictions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckAugment(Parser *parser, Object *object) { if (! object->relatedPtr) { return; } if (object->relatedPtr->export.nodekind != SMI_NODEKIND_ROW) { smiPrintErrorAtLine(parser, ERR_AUGMENT_NO_ROW, object->line, object->export.name, object->relatedPtr->export.name); return; } if (object->relatedPtr->export.indexkind == SMI_INDEX_INDEX) return; if (object->export.indexkind == SMI_INDEX_AUGMENT) { smiPrintErrorAtLine(parser, ERR_AUGMENT_NESTED, object->line, object->export.name, object->relatedPtr->export.name); return; } if (object->relatedPtr->export.indexkind != SMI_INDEX_SPARSE) { smiPrintErrorAtLine(parser, ERR_EXTENDS_WRONG_ROW_TYPE, object->line, object->export.name, object->relatedPtr->export.name); return; } /* * TODO: Check the size of the instance identifier and the OID * for this entry node. */ } /* *---------------------------------------------------------------------- * * smiCheckTypeRanges -- * * Check whether all ranges of a given type are valid. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckTypeRanges(Parser *parser, Type *type) { List *p, *nextPtr, *pp, *nextPP; for (p = type->listPtr; p; p = nextPtr) { nextPtr = p->nextPtr; ((Range *)p->ptr)->typePtr = type; if (type->export.basetype == SMI_BASETYPE_INTEGER32) { if ((((Range *)p->ptr)->export.minValue.basetype == SMI_BASETYPE_UNSIGNED32) && (((Range *)p->ptr)->export.minValue.value.unsigned32 > 2147483647)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } if ((((Range *)p->ptr)->export.maxValue.basetype == SMI_BASETYPE_UNSIGNED32) && (((Range *)p->ptr)->export.maxValue.value.unsigned32 > 2147483647)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } ((Range *)p->ptr)->export.minValue.basetype = SMI_BASETYPE_INTEGER32; ((Range *)p->ptr)->export.maxValue.basetype = SMI_BASETYPE_INTEGER32; } if (type->export.basetype == SMI_BASETYPE_UNSIGNED32) { if ((((Range *)p->ptr)->export.minValue.basetype == SMI_BASETYPE_INTEGER32) && (((Range *)p->ptr)->export.minValue.value.integer32 < 0)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } if ((((Range *)p->ptr)->export.maxValue.basetype == SMI_BASETYPE_INTEGER32) && (((Range *)p->ptr)->export.maxValue.value.integer32 < 0)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } ((Range *)p->ptr)->export.minValue.basetype = SMI_BASETYPE_UNSIGNED32; ((Range *)p->ptr)->export.maxValue.basetype = SMI_BASETYPE_UNSIGNED32; } if (type->export.basetype == SMI_BASETYPE_OCTETSTRING) { if ((((Range *)p->ptr)->export.minValue.basetype == SMI_BASETYPE_INTEGER32) && (((Range *)p->ptr)->export.minValue.value.integer32 < 0)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } if ((((Range *)p->ptr)->export.maxValue.basetype == SMI_BASETYPE_INTEGER32) && (((Range *)p->ptr)->export.maxValue.value.integer32 < 0)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } if ((((Range *)p->ptr)->export.minValue.basetype == SMI_BASETYPE_UNSIGNED32) && (((Range *)p->ptr)->export.minValue.value.unsigned32 > 65535)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } if ((((Range *)p->ptr)->export.maxValue.basetype == SMI_BASETYPE_UNSIGNED32) && (((Range *)p->ptr)->export.maxValue.value.unsigned32 > 65535)) { smiPrintError(parser, ERR_RANGE_OUT_OF_BASETYPE); } ((Range *)p->ptr)->export.minValue.basetype = SMI_BASETYPE_UNSIGNED32; ((Range *)p->ptr)->export.maxValue.basetype = SMI_BASETYPE_UNSIGNED32; } if (compareValues(&((Range *)p->ptr)->export.minValue, &((Range *)p->ptr)->export.maxValue) > 0) { SmiValue v; v = ((Range *)p->ptr)->export.minValue; ((Range *)p->ptr)->export.minValue = ((Range *)p->ptr)->export.maxValue; ((Range *)p->ptr)->export.maxValue = v; smiPrintError(parser, ERR_EXCHANGED_RANGE_LIMITS); } /* sort */ p->nextPtr = NULL; if (p != type->listPtr) { if (compareValues(&((Range *)p->ptr)->export.minValue, &((Range *)type->listPtr->ptr)->export.minValue) <= 0) { if (compareValues(&((Range *)p->ptr)->export.maxValue, &((Range *)type->listPtr->ptr)->export.minValue) >= 0) { smiPrintError(parser, ERR_RANGE_OVERLAP); } smiPrintError(parser, ERR_RANGES_NOT_ASCENDING); p->nextPtr = type->listPtr; type->listPtr = p; } else { for (pp = type->listPtr; pp; pp = nextPP) { nextPP = pp->nextPtr; if ((!nextPP) || (compareValues(&((Range *)p->ptr)->export.minValue, &((Range *)nextPP->ptr)->export.minValue) <= 0)) { if (((nextPP) && (compareValues(&((Range *)p->ptr)->export.maxValue, &((Range *)nextPP->ptr)->export.minValue) >= 0)) || (compareValues(&((Range *)p->ptr)->export.minValue, &((Range *)pp->ptr)->export.maxValue) <= 0)) { smiPrintError(parser, ERR_RANGE_OVERLAP); } p->nextPtr = pp->nextPtr; pp->nextPtr = p; if (p->nextPtr) { smiPrintError(parser, ERR_RANGES_NOT_ASCENDING); pp->nextPtr = NULL; } break; } } } } } /* range normalization */ for (p = type->listPtr, pp = p; p; p = nextPtr) { nextPtr = p->nextPtr; if (nextPtr && compareValues(&((Range *)p->ptr)->export.maxValue, &((Range *)nextPtr->ptr)->export.minValue) == -1) { ((Range *)nextPtr->ptr)->export.minValue = ((Range *)p->ptr)->export.minValue; if (p == type->listPtr) { type->listPtr = nextPtr; pp = nextPtr; } else { pp->nextPtr = nextPtr; } smiFree(p); } else { pp = p; } } } /* *---------------------------------------------------------------------- * * smiCheckTypeFormat -- * * Check whether we know a format specification for integer types. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckTypeFormat(Parser *parser, Type *type) { Type *t; if (! type || !type->export.name) { return; } if (type->export.basetype != SMI_BASETYPE_INTEGER32 && type->export.basetype != SMI_BASETYPE_INTEGER64 && type->export.basetype != SMI_BASETYPE_UNSIGNED32 && type->export.basetype != SMI_BASETYPE_UNSIGNED64 && type->export.basetype != SMI_BASETYPE_OCTETSTRING) { return; } for (t = type; t; t = t->parentPtr) { if (t->export.format) { break; } } if (! t) { smiPrintErrorAtLine(parser, ERR_TYPE_WITHOUT_FORMAT, type->line, type->export.name); } } /* *---------------------------------------------------------------------- * * smiCheckValueType -- * * Check whether a given value matches a given type. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckValueType(Parser *parser, SmiValue *value, Type *type, int line) { List *p, *nextPtr; if (value && (value->basetype != SMI_BASETYPE_UNKNOWN) && type) { /* * If defval type and object type don't match, check whether * the defval value is in the allowed range of the object's basetype. */ if ((type->export.basetype == SMI_BASETYPE_INTEGER32) || (type->export.basetype == SMI_BASETYPE_ENUM)) { if (((value->basetype == SMI_BASETYPE_INTEGER64) && ((value->value.integer64 < (SmiInteger64)(-2147483647 - 1)) || (value->value.integer64 > (SmiInteger64)2147483647))) || ((value->basetype == SMI_BASETYPE_UNSIGNED32) && ((value->value.unsigned32 > 2147483647))) || ((value->basetype == SMI_BASETYPE_UNSIGNED64) && ((value->value.unsigned32 > 2147483647)))) { smiPrintErrorAtLine(parser, ERR_DEFVAL_OUT_OF_BASETYPE, line); } } if (type->export.basetype == SMI_BASETYPE_UNSIGNED32) { if (((value->basetype == SMI_BASETYPE_INTEGER64) && ((value->value.integer64 < 0) || (value->value.integer64 > (SmiInteger64)4294967295UL))) || ((value->basetype == SMI_BASETYPE_INTEGER32) && ((value->value.integer32 < 0))) || ((value->basetype == SMI_BASETYPE_UNSIGNED64) && ((value->value.unsigned32 > (SmiUnsigned32)4294967295UL)))) { smiPrintErrorAtLine(parser, ERR_DEFVAL_OUT_OF_BASETYPE, line); } } /* * "cast" the defval to the object's basetype. */ value->basetype = type->export.basetype; /* * check whether the defval matches the object's range restriction. */ if ((value->basetype == SMI_BASETYPE_UNSIGNED32) || (value->basetype == SMI_BASETYPE_UNSIGNED64) || (value->basetype == SMI_BASETYPE_INTEGER32) || (value->basetype == SMI_BASETYPE_INTEGER64)) { for (p = type->listPtr; p; p = nextPtr) { nextPtr = p->nextPtr; if ((compareValues(&((Range *)p->ptr)->export.minValue, value) <= 0) && (compareValues(&((Range *)p->ptr)->export.maxValue, value) >= 0)) { break; } } if ((p == NULL) && type->listPtr) { smiPrintErrorAtLine(parser, ERR_DEFVAL_OUT_OF_RANGE, line); } } /* * check whether the defval matches the object's enumeration. */ if (value->basetype == SMI_BASETYPE_ENUM) { for (p = type->listPtr; p; p = nextPtr) { nextPtr = p->nextPtr; if (((NamedNumber *)(p->ptr))->export.value.value.integer32 == value->value.integer32) { break; } } if (p == NULL) { smiPrintErrorAtLine(parser, ERR_DEFVAL_OUT_OF_ENUM, line); } } } } /* *---------------------------------------------------------------------- * * smiCheckDefault -- * * Check whether the default value (if present) matches the * underlying type and restrictions. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckDefault(Parser *parser, Object *object) { smiCheckValueType(parser, &object->export.value, object->typePtr, object->line); } /* *---------------------------------------------------------------------- * * smiCheckTypeUsage -- * * Check whether the types of all objects are used appropriately. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ static void checkInetAddressType(Parser *parserPtr, Module *modulePtr, Object *objectPtr) { Module *inetModulePtr = NULL; /* RFC 3291 */ Type *inetAddressTypePtr = NULL; /* RFC 3291 */ Type *inetAddressPtr = NULL; /* RFC 3291 */ Node *nodePtr; List *listPtr = NULL; int i; const char *protected[] = { "InetAddressIPv4", "InetAddressIPv6", "InetAddressIPv4z", "InetAddressIPv6z", "InetAddressDNS", NULL }; inetModulePtr = findModuleByName("INET-ADDRESS-MIB"); if (! inetModulePtr) { return; } inetAddressTypePtr = findTypeByModuleAndName(inetModulePtr, "InetAddressType"); inetAddressPtr = findTypeByModuleAndName(inetModulePtr, "InetAddress"); if (!inetAddressTypePtr || !inetAddressPtr) { return; } /* check InetAddressType/InetAddress pair */ if (smiTypeDerivedFrom(objectPtr->typePtr, inetAddressPtr)) { Object *indexObject = NULL; Object *entryObject = objectPtr->nodePtr->parentPtr->lastObjectPtr; if (entryObject) { switch (entryObject->export.indexkind) { case SMI_INDEX_INDEX: indexObject = entryObject; break; case SMI_INDEX_AUGMENT: indexObject = entryObject->relatedPtr; break; default: /* xxx need to handle other index constructions */ indexObject = NULL; break; } } if (indexObject) { for (listPtr = indexObject->listPtr; listPtr; listPtr = listPtr->nextPtr) { Object *iObject = (Object *) listPtr->ptr; if (iObject && iObject->typePtr == inetAddressTypePtr) { break; } } } if (! indexObject || ! listPtr) { for (nodePtr = objectPtr->nodePtr->parentPtr->firstChildPtr; nodePtr && nodePtr->subid < objectPtr->nodePtr->subid && nodePtr->lastObjectPtr->typePtr != inetAddressTypePtr; nodePtr = nodePtr->nextPtr); if (!nodePtr || nodePtr->subid >= objectPtr->nodePtr->subid) { smiPrintErrorAtLine(parserPtr, ERR_INETADDRESS_WITHOUT_TYPE, objectPtr->line); } } } /* check InetAddressType subtyping */ if (objectPtr->typePtr->parentPtr == inetAddressTypePtr) { smiPrintErrorAtLine(parserPtr, ERR_INETADDRESSTYPE_SUBTYPED, objectPtr->line); } /* check for TCs that should not be used directly */ for (i = 0; protected[i]; i++) { if (objectPtr->typePtr == findTypeByModuleAndName(inetModulePtr, protected[i])) { smiPrintErrorAtLine(parserPtr, ERR_INETADDRESS_SPECIFIC, objectPtr->line, objectPtr->typePtr->export.name); break; } } } static void checkTransportAddressType(Parser *parserPtr, Module *modulePtr, Object *objectPtr) { Module *transportModulePtr = NULL; /* RFC 3419 */ Type *transportAddressTypePtr = NULL; /* RFC 3419 */ Type *transportAddressPtr = NULL; /* RFC 3419 */ Type *transportDomainPtr = NULL; /* RFC 3419 */ Node *nodePtr; List *listPtr = NULL; int i; const char *protected[] = { "TransportAddressIPv4", "TransportAddressIPv6", "TransportAddressIPv4z", "TransportAddressIPv6z", "TransportAddressDNS", "TransportAddressLocal", NULL }; transportModulePtr = findModuleByName("TRANSPORT-ADDRESS-MIB"); if (! transportModulePtr) { return; } transportAddressTypePtr = findTypeByModuleAndName(transportModulePtr, "TransportAddressType"); transportAddressPtr = findTypeByModuleAndName(transportModulePtr, "TransportAddress"); transportDomainPtr = findTypeByModuleAndName(transportModulePtr, "TransportDomain"); if (!transportAddressTypePtr || !transportAddressPtr || !transportDomainPtr) { return; } /* check TransportAddressType/TransportAddress pair */ if (smiTypeDerivedFrom(objectPtr->typePtr, transportAddressPtr)) { Object *indexObject = NULL; Object *entryObject = objectPtr->nodePtr->parentPtr->lastObjectPtr; if (entryObject) { switch (entryObject->export.indexkind) { case SMI_INDEX_INDEX: indexObject = entryObject; break; case SMI_INDEX_AUGMENT: indexObject = entryObject->relatedPtr; break; default: /* xxx need to handle other index constructions */ indexObject = NULL; break; } } if (indexObject) { for (listPtr = indexObject->listPtr; listPtr; listPtr = listPtr->nextPtr) { Object *iObject = (Object *) listPtr->ptr; if (iObject && (iObject->typePtr == transportAddressTypePtr || iObject->typePtr == transportDomainPtr)) { break; } } } if (! indexObject || ! listPtr) { for (nodePtr = objectPtr->nodePtr->parentPtr->firstChildPtr; nodePtr && nodePtr->subid < objectPtr->nodePtr->subid && nodePtr->lastObjectPtr->typePtr != transportAddressTypePtr && nodePtr->lastObjectPtr->typePtr != transportDomainPtr; nodePtr = nodePtr->nextPtr); if (!nodePtr || nodePtr->subid >= objectPtr->nodePtr->subid) { smiPrintErrorAtLine(parserPtr, ERR_TRANSPORTADDRESS_WITHOUT_TYPE, objectPtr->line); } } } /* check TransportAddressType subtyping */ if (objectPtr->typePtr->parentPtr == transportAddressTypePtr) { smiPrintErrorAtLine(parserPtr, ERR_TRANSPORTADDRESSTYPE_SUBTYPED, objectPtr->line); } /* check for TCs that should not be used directly */ for (i = 0; protected[i]; i++) { if (objectPtr->typePtr == findTypeByModuleAndName(transportModulePtr, protected[i])) { smiPrintErrorAtLine(parserPtr, ERR_TRANSPORTADDRESS_SPECIFIC, objectPtr->line, objectPtr->typePtr->export.name); break; } } } void smiCheckTypeUsage(Parser *parserPtr, Module *modulePtr) { Object *objectPtr; Module *tcModulePtr = NULL; Type *rowStatusPtr = NULL; Type *storageTypePtr = NULL; Type *taddressPtr = NULL; Type *tdomainPtr = NULL; NamedNumber *nnPtr; Node *nodePtr; tcModulePtr = findModuleByName("SNMPv2-TC"); if (tcModulePtr) { rowStatusPtr = findTypeByModuleAndName(tcModulePtr, "RowStatus"); storageTypePtr = findTypeByModuleAndName(tcModulePtr, "StorageType"); taddressPtr = findTypeByModuleAndName(tcModulePtr, "TAddress"); tdomainPtr = findTypeByModuleAndName(tcModulePtr, "TDomain"); } for (objectPtr = modulePtr->firstObjectPtr; objectPtr; objectPtr = objectPtr->nextPtr) { if (objectPtr->typePtr) { if (tcModulePtr) { /* check RowStatus DEFVAL */ if (objectPtr->typePtr == rowStatusPtr) { if ((objectPtr->export.value.value.integer32 >= 4) && (objectPtr->export.value.value.integer32 <= 6)) { nnPtr = findTypeNamedNumber(rowStatusPtr, objectPtr->export.value.value.integer32); smiPrintErrorAtLine(parserPtr, ERR_ILLEGAL_ROWSTATUS_DEFAULT, objectPtr->line, nnPtr->export.name); } } /* check RowStatus read-create status */ if (objectPtr->typePtr == rowStatusPtr) { Object *entryObject = objectPtr->nodePtr->parentPtr->lastObjectPtr; if (objectPtr->export.access != SMI_ACCESS_READ_WRITE || !entryObject->export.create) { smiPrintErrorAtLine(parserPtr, ERR_ILLEGAL_ROWSTATUS_ACCESS, objectPtr->line); } } /* check StorageType DEFVAL */ if (objectPtr->typePtr == storageTypePtr) { if ((objectPtr->export.value.value.integer32 >= 4) && (objectPtr->export.value.value.integer32 <= 5)) { nnPtr = findTypeNamedNumber(storageTypePtr, objectPtr->export.value.value.integer32); smiPrintErrorAtLine(parserPtr, ERR_ILLEGAL_STORAGETYPE_DEFAULT, objectPtr->line, nnPtr->export.name); } } /* check TDomain/TAddress pair */ if (smiTypeDerivedFrom(objectPtr->typePtr, taddressPtr)) { for (nodePtr = objectPtr->nodePtr->parentPtr->firstChildPtr; nodePtr && nodePtr->lastObjectPtr->typePtr != tdomainPtr; nodePtr = nodePtr->nextPtr); if (!nodePtr || nodePtr->lastObjectPtr->typePtr != tdomainPtr) { smiPrintErrorAtLine(parserPtr, ERR_TADDRESS_WITHOUT_TDOMAIN, objectPtr->line); } } } checkInetAddressType(parserPtr, modulePtr, objectPtr); checkTransportAddressType(parserPtr, modulePtr, objectPtr); } } } static char *status[] = { "Unknown", "current", "deprecated", "mandatory", "optional", "obsolete" }; static int memberOfGroup(Object *object, Object *group) { List *listPtr; for (listPtr = group->listPtr; listPtr; listPtr = listPtr->nextPtr) { if (listPtr->ptr == object) { return 1; } } return 0; } /* *---------------------------------------------------------------------- * * smiCheckComplianceStatus -- * * Make sure that all groups and objects in a compliance statement * are at least as current as the compliance itself. * XXX I'm not sure I traversed the whole compliance statement, * this at least covers the common case * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckComplianceStatus(Parser *parser, Object *compliance) { List *listPtr, *groupListPtr; Object *memberPtr; Object *group; for (listPtr = compliance->listPtr; listPtr; listPtr = listPtr->nextPtr) { memberPtr = (Object *) listPtr->ptr; if (!memberPtr) continue; addObjectFlags(memberPtr, FLAG_INCOMPLIANCE); if (memberPtr->export.status > compliance->export.status) { smiPrintErrorAtLine(parser, ERR_COMPLIANCE_GROUP_STATUS, compliance->line, status[compliance->export.status], compliance->export.name, status[memberPtr->export.status], memberPtr->export.name); } } for (listPtr = compliance->optionlistPtr; listPtr; listPtr = listPtr->nextPtr) { memberPtr = ((Option *) listPtr->ptr)->objectPtr; addObjectFlags(memberPtr, FLAG_INCOMPLIANCE); if (memberPtr->export.status > compliance->export.status) { smiPrintErrorAtLine(parser, ERR_COMPLIANCE_GROUP_STATUS, ((Option *) listPtr->ptr)->line, status[compliance->export.status], compliance->export.name, status[memberPtr->export.status], memberPtr->export.name); } } for (listPtr = compliance->refinementlistPtr; listPtr; listPtr = listPtr->nextPtr) { memberPtr = ((Refinement *) listPtr->ptr)->objectPtr; for (groupListPtr = compliance->listPtr; groupListPtr; groupListPtr = groupListPtr->nextPtr) { group = (Object *) groupListPtr->ptr; if (group && memberOfGroup(memberPtr, group)) { break; } } if (! groupListPtr) { for (groupListPtr = compliance->optionlistPtr; groupListPtr; groupListPtr = groupListPtr->nextPtr) { group = ((Option *) groupListPtr->ptr)->objectPtr; if (group && memberOfGroup(memberPtr, group)) { break; } } } if (! groupListPtr) { smiPrintErrorAtLine(parser, ERR_REFINEMENT_NOT_LISTED, ((Refinement *) listPtr->ptr)->line, memberPtr->export.name); } addObjectFlags(memberPtr, FLAG_INCOMPLIANCE); if (memberPtr->export.status > compliance->export.status) { smiPrintErrorAtLine(parser, ERR_COMPLIANCE_OBJECT_STATUS, ((Refinement *) listPtr->ptr)->line, status[compliance->export.status], compliance->export.name, status[memberPtr->export.status], memberPtr->export.name); } } } /* *---------------------------------------------------------------------- * * smiCheckGroupMembers -- * * Check whether only scalar and column nodes and notifications * are contained in a conformance group. * * Also ensure that group members are at least as current * as the group itself. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckGroupMembers(Parser *parser, Object *group) { List *listPtr; Object *memberPtr; int scalarsOrColumns = 0; int notifications = 0; for (listPtr = group->listPtr; listPtr; listPtr = listPtr->nextPtr) { memberPtr = (Object *) listPtr->ptr; if (((memberPtr->export.nodekind == SMI_NODEKIND_COLUMN || memberPtr->export.nodekind == SMI_NODEKIND_SCALAR) && memberPtr->export.access != SMI_ACCESS_NOT_ACCESSIBLE) || memberPtr->export.nodekind == SMI_NODEKIND_NOTIFICATION) { if (memberPtr->export.nodekind == SMI_NODEKIND_NOTIFICATION) { notifications++; if (group->export.decl == SMI_DECL_OBJECTGROUP) { smiPrintErrorAtLine(parser, ERR_NOTIFICATION_IN_OBJECT_GROUP, group->line, group->export.name, memberPtr->export.name); } } else { scalarsOrColumns++; if (group->export.decl == SMI_DECL_NOTIFICATIONGROUP) { smiPrintErrorAtLine(parser, ERR_OBJECT_IN_NOTIFICATION_GROUP, group->line, group->export.name, memberPtr->export.name); } } addObjectFlags(memberPtr, FLAG_INGROUP); } else if (!(memberPtr->flags & FLAG_INCOMPLETE)) { /* unknown OIDs are already flagged */ smiPrintErrorAtLine(parser, ERR_INVALID_GROUP_MEMBER, group->line, memberPtr->export.name, group->export.name); } if (memberPtr->export.status > group->export.status) { smiPrintErrorAtLine(parser, ERR_GROUP_OBJECT_STATUS, group->line, status[group->export.status], group->export.name, status[memberPtr->export.status], memberPtr->export.name); } } if (scalarsOrColumns && notifications) { smiPrintErrorAtLine(parser, ERR_MIXED_GROUP_MEMBERS, group->line, group->export.name); } } /* *---------------------------------------------------------------------- * * smiCheckGroupMembership -- * * Check whether scalar and column nodes and notifications are * contained in at least one conformance group. * * This function assumes that smiCheckGroupMembers() has been * called on all group objects and smiCheckComplianceStatus() * has been called on all compliance objects before. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckGroupMembership(Parser *parser, Object *objectPtr) { int found; if (((objectPtr->export.nodekind == SMI_NODEKIND_COLUMN || objectPtr->export.nodekind == SMI_NODEKIND_SCALAR) && objectPtr->export.access != SMI_ACCESS_NOT_ACCESSIBLE) || objectPtr->export.nodekind == SMI_NODEKIND_NOTIFICATION) { found = (objectPtr->flags & FLAG_INGROUP); if (! found) { if (objectPtr->export.nodekind == SMI_NODEKIND_NOTIFICATION) { smiPrintErrorAtLine(parser, ERR_NOTIFICATION_NOT_IN_GROUP, objectPtr->line, objectPtr->export.name); } else { smiPrintErrorAtLine(parser, ERR_NODE_NOT_IN_GROUP, objectPtr->line, objectPtr->export.name); } } } if (objectPtr->export.nodekind == SMI_NODEKIND_GROUP) { found = (objectPtr->flags & FLAG_INCOMPLIANCE); if (!found && objectPtr->export.status != SMI_STATUS_OBSOLETE) { smiPrintErrorAtLine(parser, ERR_GROUP_UNREF, objectPtr->line, status[objectPtr->export.status], objectPtr->export.name); } } } /* *---------------------------------------------------------------------- * * smiCheckObjectReuse -- * * Check whether a newly defined Object represents a duplicate * or a reused OID. * * Results: * None. * * Side effects: * Allocates a new Object and adjusts the objectPtr parameter. * *---------------------------------------------------------------------- */ void smiCheckObjectReuse(Parser *parser, char *name, Object **objectPtr) { if ((((*objectPtr)->flags & FLAG_INCOMPLETE) == 0) && strcmp(name, (*objectPtr)->export.name)) { if ((*objectPtr)->export.decl >= SMI_DECL_OBJECTTYPE) { smiPrintError(parser, ERR_OID_REGISTERED, name, (*objectPtr)->export.name); } else { smiPrintError(parser, ERR_OID_REUSE, name, (*objectPtr)->export.name); } smiPrintErrorAtLine(parser, ERR_PREVIOUS_DEFINITION, (*objectPtr)->line, (*objectPtr)->export.name); *objectPtr = duplicateObject(*objectPtr, 0, parser); } if ((*objectPtr)->modulePtr != parser->modulePtr) { *objectPtr = duplicateObject(*objectPtr, 0, parser); } } /* *---------------------------------------------------------------------- * * smiCheckNotificationOid -- * * Check whether SMIv2 notifications are reversible and whether * the last sub-identifer fits into a signed 32-bit integer. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckNotificationOid(Parser *parser, Module *module, Object *object) { static const char *name[] = { "SNMPv2-MIB", "coldStart", "SNMPv2-MIB", "warmStart", "IF-MIB", "linkDown", "IF-MIB", "linkUp", "SNMPv2-MIB", "authenticationFailure", /* egpNeighborLoss is not really defined in any SMI module */ NULL, NULL }; int i; if (parser->modulePtr->export.language == SMI_LANGUAGE_SMIV2) { for (i = 0; name[i]; i+= 2) { if (strcmp(name[i], module->export.name) == 0 && strcmp(name[i+1], object->export.name) == 0) { break; } } if (! name[i]) { Node *parent = object->nodePtr->parentPtr; if (parent && parent->subid != 0) { smiPrintErrorAtLine(parser, ERR_NOTIFICATION_NOT_REVERSIBLE, object->line, object->export.name); } } } if (object->nodePtr->subid > 2147483647) { smiPrintErrorAtLine(parser, ERR_NOTIFICATION_ID_TOO_LARGE, object->line, object->export.name); } } /* *---------------------------------------------------------------------- * * smiCheckNotificationMembers -- * * Check whether a newly defined notification contains only members * of a single logical object. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckNotificationMembers(Parser *parser, Object *object) { List *listPtr; Object *memberPtr; #if 0 Node *parent = NULL; #endif Node *node = NULL; for (listPtr = object->listPtr; listPtr; listPtr = listPtr->nextPtr) { memberPtr = (Object *) listPtr->ptr; if (memberPtr->export.nodekind == SMI_NODEKIND_SCALAR) { if (memberPtr->nodePtr && memberPtr->nodePtr->parentPtr) { node = memberPtr->nodePtr->parentPtr; } } else if (memberPtr->export.nodekind == SMI_NODEKIND_COLUMN) { if (memberPtr->nodePtr && memberPtr->nodePtr->parentPtr && memberPtr->nodePtr->parentPtr->parentPtr) { node = memberPtr->nodePtr->parentPtr->parentPtr; } } else { smiPrintErrorAtLine(parser, ERR_NOTIFICATION_OBJECT_TYPE, object->line, memberPtr->export.name, object->export.name); } if (memberPtr->export.access == SMI_ACCESS_NOT_ACCESSIBLE) { smiPrintErrorAtLine(parser, ERR_NOTIFICATION_OBJECT_ACCESS, object->line, memberPtr->export.name, object->export.name); } /* xxx check for duplicates */ #if 0 if (node) { if (! parent) { parent = node; } else { if (parent != node) { /* xxx do not report multiple times xxx */ smiPrintErrorAtLine(parser, ERR_NOTIFICATION_OBJECT_MIX, object->line, object->export.name); } } } #endif } } /* *---------------------------------------------------------------------- * * smiCheckUniqueness -- * * Check whether all entries for an UNIQUENESS clause are in fact * columns. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckUniqueness(Parser *parser, Object *object) { List *p; for (p = object->uniquenessPtr; p; p = p->nextPtr) { Object *uniq = (Object *)p->ptr; int found = 0; List *pp; if (uniq && object->typePtr) { for (pp = object->typePtr->listPtr; pp; pp = pp->nextPtr) if (pp->ptr && !strcmp(uniq->export.name, ((Object *)pp->ptr)->export.name)) { found = 1; break; } if (!found) { if (((object->export.indexkind == SMI_INDEX_AUGMENT) || (object->export.indexkind == SMI_INDEX_SPARSE)) && (object->relatedPtr && object->relatedPtr->typePtr)) { for (pp = object->relatedPtr->typePtr->listPtr; pp; pp = pp->nextPtr) if (pp->ptr && !strcmp(uniq->export.name, ((Object *)pp->ptr)->export.name)) { found = 1; break; } } } if (!found) smiPrintErrorAtLine(parser, ERR_NOT_A_COLUMN, object->line, uniq->export.name); } } } /* *---------------------------------------------------------------------- * * smiCheckModuleIdentityRegistration -- * * Check whether the module identity is registered in a well * known (IANA) controlled location. In particular, warn if * the OID is below iso(1).org(3).dod(6).mgmt(1) and not * below well known registration locations such as mib-2, * transmission, or snmpModules. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------- */ void smiCheckModuleIdentityRegistration(Parser *parser, Object *object) { static const SmiSubid mgmt[] = { 1, 3, 6, 1, 2 }; static const SmiSubid mib2[] = { 1, 3, 6, 1, 2, 1 }; static const SmiSubid transmission[] = { 1, 3, 6, 1, 2, 1, 10 }; static const SmiSubid snmpModules[] = { 1, 3, 6, 1, 6, 3 }; if (object->export.oidlen < sizeof(mgmt)/sizeof(SmiSubid) || memcmp(object->export.oid, mgmt, sizeof(mgmt)) != 0) { return; } if (object->export.oidlen == sizeof(mib2)/sizeof(SmiSubid) + 1 && memcmp(object->export.oid, mib2, sizeof(mib2)) == 0) { return; } if (object->export.oidlen == sizeof(transmission)/sizeof(SmiSubid) + 1 && memcmp(object->export.oid, transmission, sizeof(transmission)) == 0) { return; } if (object->export.oidlen == sizeof(snmpModules)/sizeof(SmiSubid) + 1 && memcmp(object->export.oid, snmpModules, sizeof(snmpModules)) == 0) { return; } smiPrintErrorAtLine(parser, ERR_MODULE_IDENTITY_REGISTRATION, object->line); } /* *---------------------------------------------------------------------- * * smiyyerror -- * * Prints an error message from the parser. In SMIv1 and v2, * a common error is to terminate a comment early, so if the * current line contains a comment (parserPtr->lcline) print * the ERR_COMMENT_TERMINATES. * *---------------------------------------------------------------------- */ void smiyyerror(char *msg, Parser *parserPtr) { if (parserPtr->line == parserPtr->lcline && parserPtr->modulePtr && (parserPtr->modulePtr->export.language == SMI_LANGUAGE_SMIV1 || parserPtr->modulePtr->export.language == SMI_LANGUAGE_SMIV2)) smiPrintError(parserPtr, ERR_COMMENT_TERMINATES); smiPrintError(parserPtr, ERR_OTHER_ERROR, msg); }