[BACK]Return to smi.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / snmp

Annotation of src/usr.bin/snmp/smi.c, Revision 1.1

1.1     ! martijn     1: /*     $OpenBSD$       */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
        !             5:  * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
        !             6:  *
        !             7:  * Permission to use, copy, modify, and distribute this software for any
        !             8:  * purpose with or without fee is hereby granted, provided that the above
        !             9:  * copyright notice and this permission notice appear in all copies.
        !            10:  *
        !            11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19:
        !            20: #include <sys/limits.h>
        !            21: #include <sys/tree.h>
        !            22: #include <sys/queue.h>
        !            23:
        !            24: #include <arpa/inet.h>
        !            25:
        !            26: #include <ctype.h>
        !            27: #include <stdlib.h>
        !            28: #include <stdio.h>
        !            29: #include <string.h>
        !            30: #include <strings.h>
        !            31:
        !            32: #include "ber.h"
        !            33: #include "mib.h"
        !            34: #include "snmp.h"
        !            35: #include "smi.h"
        !            36:
        !            37: #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
        !            38:
        !            39: int smi_oid_cmp(struct oid *, struct oid *);
        !            40: int smi_key_cmp(struct oid *, struct oid *);
        !            41: struct oid * smi_findkey(char *);
        !            42:
        !            43: RB_HEAD(oidtree, oid);
        !            44: RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp)
        !            45: struct oidtree smi_oidtree;
        !            46:
        !            47: RB_HEAD(keytree, oid);
        !            48: RB_PROTOTYPE(keytree, oid, o_keyword, smi_key_cmp)
        !            49: struct keytree smi_keytree;
        !            50:
        !            51: int
        !            52: smi_init(void)
        !            53: {
        !            54:        /* Initialize the Structure of Managed Information (SMI) */
        !            55:        RB_INIT(&smi_oidtree);
        !            56:        mib_init();
        !            57:        return (0);
        !            58: }
        !            59:
        !            60: void
        !            61: smi_debug_elements(struct ber_element *root)
        !            62: {
        !            63:        static int       indent = 0;
        !            64:        char            *value;
        !            65:        int              constructed;
        !            66:
        !            67:        /* calculate lengths */
        !            68:        ber_calc_len(root);
        !            69:
        !            70:        switch (root->be_encoding) {
        !            71:        case BER_TYPE_SEQUENCE:
        !            72:        case BER_TYPE_SET:
        !            73:                constructed = root->be_encoding;
        !            74:                break;
        !            75:        default:
        !            76:                constructed = 0;
        !            77:                break;
        !            78:        }
        !            79:
        !            80:        fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
        !            81:        switch (root->be_class) {
        !            82:        case BER_CLASS_UNIVERSAL:
        !            83:                fprintf(stderr, "class: universal(%u) type: ", root->be_class);
        !            84:                switch (root->be_type) {
        !            85:                case BER_TYPE_EOC:
        !            86:                        fprintf(stderr, "end-of-content");
        !            87:                        break;
        !            88:                case BER_TYPE_BOOLEAN:
        !            89:                        fprintf(stderr, "boolean");
        !            90:                        break;
        !            91:                case BER_TYPE_INTEGER:
        !            92:                        fprintf(stderr, "integer");
        !            93:                        break;
        !            94:                case BER_TYPE_BITSTRING:
        !            95:                        fprintf(stderr, "bit-string");
        !            96:                        break;
        !            97:                case BER_TYPE_OCTETSTRING:
        !            98:                        fprintf(stderr, "octet-string");
        !            99:                        break;
        !           100:                case BER_TYPE_NULL:
        !           101:                        fprintf(stderr, "null");
        !           102:                        break;
        !           103:                case BER_TYPE_OBJECT:
        !           104:                        fprintf(stderr, "object");
        !           105:                        break;
        !           106:                case BER_TYPE_ENUMERATED:
        !           107:                        fprintf(stderr, "enumerated");
        !           108:                        break;
        !           109:                case BER_TYPE_SEQUENCE:
        !           110:                        fprintf(stderr, "sequence");
        !           111:                        break;
        !           112:                case BER_TYPE_SET:
        !           113:                        fprintf(stderr, "set");
        !           114:                        break;
        !           115:                }
        !           116:                break;
        !           117:        case BER_CLASS_APPLICATION:
        !           118:                fprintf(stderr, "class: application(%u) type: ",
        !           119:                    root->be_class);
        !           120:                switch (root->be_type) {
        !           121:                case SNMP_T_IPADDR:
        !           122:                        fprintf(stderr, "ipaddr");
        !           123:                        break;
        !           124:                case SNMP_T_COUNTER32:
        !           125:                        fprintf(stderr, "counter32");
        !           126:                        break;
        !           127:                case SNMP_T_GAUGE32:
        !           128:                        fprintf(stderr, "gauge32");
        !           129:                        break;
        !           130:                case SNMP_T_TIMETICKS:
        !           131:                        fprintf(stderr, "timeticks");
        !           132:                        break;
        !           133:                case SNMP_T_OPAQUE:
        !           134:                        fprintf(stderr, "opaque");
        !           135:                        break;
        !           136:                case SNMP_T_COUNTER64:
        !           137:                        fprintf(stderr, "counter64");
        !           138:                        break;
        !           139:                }
        !           140:                break;
        !           141:        case BER_CLASS_CONTEXT:
        !           142:                fprintf(stderr, "class: context(%u) type: ",
        !           143:                    root->be_class);
        !           144:                switch (root->be_type) {
        !           145:                case SNMP_C_GETREQ:
        !           146:                        fprintf(stderr, "getreq");
        !           147:                        break;
        !           148:                case SNMP_C_GETNEXTREQ:
        !           149:                        fprintf(stderr, "nextreq");
        !           150:                        break;
        !           151:                case SNMP_C_GETRESP:
        !           152:                        fprintf(stderr, "getresp");
        !           153:                        break;
        !           154:                case SNMP_C_SETREQ:
        !           155:                        fprintf(stderr, "setreq");
        !           156:                        break;
        !           157:                case SNMP_C_TRAP:
        !           158:                        fprintf(stderr, "trap");
        !           159:                        break;
        !           160:                case SNMP_C_GETBULKREQ:
        !           161:                        fprintf(stderr, "getbulkreq");
        !           162:                        break;
        !           163:                case SNMP_C_INFORMREQ:
        !           164:                        fprintf(stderr, "informreq");
        !           165:                        break;
        !           166:                case SNMP_C_TRAPV2:
        !           167:                        fprintf(stderr, "trapv2");
        !           168:                        break;
        !           169:                case SNMP_C_REPORT:
        !           170:                        fprintf(stderr, "report");
        !           171:                        break;
        !           172:                }
        !           173:                break;
        !           174:        case BER_CLASS_PRIVATE:
        !           175:                fprintf(stderr, "class: private(%u) type: ", root->be_class);
        !           176:                break;
        !           177:        default:
        !           178:                fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
        !           179:                break;
        !           180:        }
        !           181:        fprintf(stderr, "(%u) encoding %u ",
        !           182:            root->be_type, root->be_encoding);
        !           183:
        !           184:        if ((value = smi_print_element(root, 1, smi_os_default, smi_oidl_numeric)) == NULL)
        !           185:                goto invalid;
        !           186:
        !           187:        switch (root->be_encoding) {
        !           188:        case BER_TYPE_BOOLEAN:
        !           189:                fprintf(stderr, "%s", value);
        !           190:                break;
        !           191:        case BER_TYPE_INTEGER:
        !           192:        case BER_TYPE_ENUMERATED:
        !           193:                fprintf(stderr, "value %s", value);
        !           194:                break;
        !           195:        case BER_TYPE_BITSTRING:
        !           196:                fprintf(stderr, "hexdump %s", value);
        !           197:                break;
        !           198:        case BER_TYPE_OBJECT:
        !           199:                fprintf(stderr, "oid %s", value);
        !           200:                break;
        !           201:        case BER_TYPE_OCTETSTRING:
        !           202:                if (root->be_class == BER_CLASS_APPLICATION &&
        !           203:                    root->be_type == SNMP_T_IPADDR) {
        !           204:                        fprintf(stderr, "addr %s", value);
        !           205:                } else {
        !           206:                        fprintf(stderr, "string %s", value);
        !           207:                }
        !           208:                break;
        !           209:        case BER_TYPE_NULL:     /* no payload */
        !           210:        case BER_TYPE_EOC:
        !           211:        case BER_TYPE_SEQUENCE:
        !           212:        case BER_TYPE_SET:
        !           213:        default:
        !           214:                fprintf(stderr, "%s", value);
        !           215:                break;
        !           216:        }
        !           217:
        !           218:  invalid:
        !           219:        if (value == NULL)
        !           220:                fprintf(stderr, "<INVALID>");
        !           221:        else
        !           222:                free(value);
        !           223:        fprintf(stderr, "\n");
        !           224:
        !           225:        if (constructed)
        !           226:                root->be_encoding = constructed;
        !           227:
        !           228:        if (constructed && root->be_sub) {
        !           229:                indent += 2;
        !           230:                smi_debug_elements(root->be_sub);
        !           231:                indent -= 2;
        !           232:        }
        !           233:        if (root->be_next)
        !           234:                smi_debug_elements(root->be_next);
        !           235: }
        !           236:
        !           237: char *
        !           238: smi_print_element(struct ber_element *root, int print_hint,
        !           239:     enum smi_output_string output_string, enum smi_oid_lookup lookup)
        !           240: {
        !           241:        char            *str = NULL, *buf, *p;
        !           242:        size_t           len, i;
        !           243:        long long        v, ticks;
        !           244:        int              d;
        !           245:        int              is_hex = 0;
        !           246:        struct ber_oid   o;
        !           247:        char             strbuf[BUFSIZ];
        !           248:        char            *hint;
        !           249:        int              days, hours, min, sec, csec;
        !           250:
        !           251:        switch (root->be_encoding) {
        !           252:        case BER_TYPE_BOOLEAN:
        !           253:                if (ber_get_boolean(root, &d) == -1)
        !           254:                        goto fail;
        !           255:                if (print_hint) {
        !           256:                        if (asprintf(&str, "INTEGER: %s(%d)",
        !           257:                            d ? "true" : "false", d) == -1)
        !           258:                                goto fail;
        !           259:                }
        !           260:                else
        !           261:                        if (asprintf(&str, "%s", d ? "true" : "false") == -1)
        !           262:                                goto fail;
        !           263:                break;
        !           264:        case BER_TYPE_INTEGER:
        !           265:        case BER_TYPE_ENUMERATED:
        !           266:                if (ber_get_integer(root, &v) == -1)
        !           267:                        goto fail;
        !           268:                if (root->be_class == BER_CLASS_APPLICATION &&
        !           269:                    root->be_type == SNMP_T_TIMETICKS) {
        !           270:                        ticks = v;
        !           271:                        days = ticks / (60 * 60 * 24 * 100);
        !           272:                        ticks %= (60 * 60 * 24 * 100);
        !           273:                        hours = ticks / (60 * 60 * 100);
        !           274:                        ticks %= (60 * 60 * 100);
        !           275:                        min = ticks / (60 * 100);
        !           276:                        ticks %= (60 * 100);
        !           277:                        sec = ticks / 100;
        !           278:                        ticks %= 100;
        !           279:                        csec = ticks;
        !           280:
        !           281:                        if (print_hint) {
        !           282:                                if (days == 0) {
        !           283:                                        if (asprintf(&str,
        !           284:                                            "Timeticks: (%lld) "
        !           285:                                            "%d:%02d:%02d.%02d",
        !           286:                                            v, hours, min, sec, csec) == -1)
        !           287:                                                goto fail;
        !           288:                                } else if (days == 1) {
        !           289:                                        if (asprintf(&str,
        !           290:                                            "Timeticks: (%lld) "
        !           291:                                            "1 day %d:%02d:%02d.%02d",
        !           292:                                            v, hours, min, sec, csec) == -1)
        !           293:                                                goto fail;
        !           294:                                } else {
        !           295:                                        if (asprintf(&str,
        !           296:                                            "Timeticks: (%lld) "
        !           297:                                            "%d day %d:%02d:%02d.%02d",
        !           298:                                            v, days, hours, min, sec, csec) ==
        !           299:                                            -1)
        !           300:                                                goto fail;
        !           301:                                }
        !           302:                        } else {
        !           303:                                if (days == 0) {
        !           304:                                        if (asprintf(&str, "%d:%02d:%02d.%02d",
        !           305:                                            hours, min, sec, csec) == -1)
        !           306:                                                goto fail;
        !           307:                                } else if (days == 1) {
        !           308:                                        if (asprintf(&str,
        !           309:                                            "1 day %d:%02d:%02d.%02d",
        !           310:                                            hours, min, sec, csec) == -1)
        !           311:                                                goto fail;
        !           312:                                } else {
        !           313:                                        if (asprintf(&str,
        !           314:                                            "%d day %d:%02d:%02d.%02d",
        !           315:                                            days, hours, min, sec, csec) == -1)
        !           316:                                                goto fail;
        !           317:                                }
        !           318:                        }
        !           319:                        break;
        !           320:                }
        !           321:                hint = "INTEGER: ";
        !           322:                if (root->be_class == BER_CLASS_APPLICATION) {
        !           323:                        if (root->be_type == SNMP_T_COUNTER32)
        !           324:                                hint = "Counter32: ";
        !           325:                        else if (root->be_type == SNMP_T_GAUGE32)
        !           326:                                hint = "Gauge32: ";
        !           327:                        else if (root->be_type == SNMP_T_OPAQUE)
        !           328:                                hint = "Opaque: ";
        !           329:                        else if (root->be_type == SNMP_T_COUNTER64)
        !           330:                                hint = "Counter64: ";
        !           331:                }
        !           332:                if (asprintf(&str, "%s%lld", print_hint ? hint : "", v)
        !           333:                    == -1)
        !           334:                        goto fail;
        !           335:                break;
        !           336:        case BER_TYPE_BITSTRING:
        !           337:                if (ber_get_bitstring(root, (void *)&buf, &len) == -1)
        !           338:                        goto fail;
        !           339:                if ((str = calloc(1, len * 2 + 1 + sizeof("BITS: "))) == NULL)
        !           340:                        goto fail;
        !           341:                p = str;
        !           342:                if (print_hint) {
        !           343:                        strlcpy(str, "BITS: ", sizeof(str));
        !           344:                        p += sizeof("BITS: ");
        !           345:                }
        !           346:                for (i = 0; i < len; i++) {
        !           347:                        snprintf(p, 3, "%02x", buf[i]);
        !           348:                        p += 2;
        !           349:                }
        !           350:                break;
        !           351:        case BER_TYPE_OBJECT:
        !           352:                if (ber_get_oid(root, &o) == -1)
        !           353:                        goto fail;
        !           354:                if (asprintf(&str, "%s%s",
        !           355:                    print_hint ? "OID: " : "",
        !           356:                    smi_oid2string(&o, strbuf, sizeof(strbuf), lookup)) == -1)
        !           357:                        goto fail;
        !           358:                break;
        !           359:        case BER_TYPE_OCTETSTRING:
        !           360:                if (ber_get_string(root, &buf) == -1)
        !           361:                        goto fail;
        !           362:                if (root->be_class == BER_CLASS_APPLICATION &&
        !           363:                    root->be_type == SNMP_T_IPADDR) {
        !           364:                        if (asprintf(&str, "%s%s",
        !           365:                            print_hint ? "IpAddress: " : "",
        !           366:                            inet_ntoa(*(struct in_addr *)buf)) == -1)
        !           367:                                goto fail;
        !           368:                } else if (root->be_class == BER_CLASS_CONTEXT &&
        !           369:                    root->be_type == BER_TYPE_EOC) {
        !           370:                        str = strdup("No Such Object available on this agent at this OID");
        !           371:
        !           372:                }else {
        !           373:                        for (i = 0; i < root->be_len; i++) {
        !           374:                                if (!isprint(buf[i])) {
        !           375:                                        if (output_string == smi_os_default)
        !           376:                                                output_string = smi_os_hex;
        !           377:                                        else if (output_string == smi_os_ascii)
        !           378:                                                is_hex = 1;
        !           379:                                        break;
        !           380:                                }
        !           381:                        }
        !           382:                        /*
        !           383:                         * hex is 3 * n (2 digits + n - 1 spaces + NUL-byte)
        !           384:                         * ascii can be max (2 * n) + 2 quotes + NUL-byte
        !           385:                         */
        !           386:                        if ((p = str = reallocarray(NULL,
        !           387:                            output_string == smi_os_hex ? 3 : 2,
        !           388:                            root->be_len + 2)) == NULL)
        !           389:                                goto fail;
        !           390:                        if (is_hex)
        !           391:                                *str++ = '"';
        !           392:                        for (i = 0; i < root->be_len; i++) {
        !           393:                                switch (output_string) {
        !           394:                                case smi_os_default:
        !           395:                                        /* FALLTHROUGH */
        !           396:                                case smi_os_ascii:
        !           397:                                        /*
        !           398:                                         * There's probably more edgecases here,
        !           399:                                         * not fully investigated
        !           400:                                         */
        !           401:                                        if (is_hex && buf[i] == '\\')
        !           402:                                                *str++ = '\\';
        !           403:                                        *str++ = isprint(buf[i]) ? buf[i] : '.';
        !           404:                                        break;
        !           405:                                case smi_os_hex:
        !           406:                                        sprintf(str, "%s%02hhX",
        !           407:                                            i == 0 ? "" :
        !           408:                                            i % 16 == 0 ? "\n" : " ", buf[i]);
        !           409:                                        str += i == 0 ? 2 : 3;
        !           410:                                        break;
        !           411:                                }
        !           412:                        }
        !           413:                        if (is_hex)
        !           414:                                *str++ = '"';
        !           415:                        *str = '\0';
        !           416:                        str = NULL;
        !           417:                        if (asprintf(&str, "%s%s",
        !           418:                            print_hint ?
        !           419:                            output_string == smi_os_hex ? "Hex-STRING: " :
        !           420:                            "STRING: " :
        !           421:                            "", p) == -1) {
        !           422:                                free(p);
        !           423:                                goto fail;
        !           424:                        }
        !           425:                        free(p);
        !           426:                }
        !           427:                break;
        !           428:        case BER_TYPE_NULL:     /* no payload */
        !           429:        case BER_TYPE_EOC:
        !           430:        case BER_TYPE_SEQUENCE:
        !           431:        case BER_TYPE_SET:
        !           432:        default:
        !           433:                str = strdup("");
        !           434:                break;
        !           435:        }
        !           436:
        !           437:        return (str);
        !           438:
        !           439:  fail:
        !           440:        free(str);
        !           441:        return (NULL);
        !           442: }
        !           443:
        !           444: int
        !           445: smi_string2oid(const char *oidstr, struct ber_oid *o)
        !           446: {
        !           447:        char                    *sp, *p, str[BUFSIZ];
        !           448:        const char              *errstr;
        !           449:        struct oid              *oid;
        !           450:        struct ber_oid           ko;
        !           451:
        !           452:        if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
        !           453:                return (-1);
        !           454:        bzero(o, sizeof(*o));
        !           455:
        !           456:        /*
        !           457:         * Parse OID strings in the common form n.n.n or n-n-n.
        !           458:         * Based on ber_string2oid with additional support for symbolic names.
        !           459:         */
        !           460:        p = sp = str[0] == '.' ? str + 1 : str;
        !           461:        for (; p != NULL; sp = p) {
        !           462:                if ((p = strpbrk(p, ".-")) != NULL)
        !           463:                        *p++ = '\0';
        !           464:                if ((oid = smi_findkey(sp)) != NULL) {
        !           465:                        bcopy(&oid->o_id, &ko, sizeof(ko));
        !           466:                        if (o->bo_n && ber_oid_cmp(o, &ko) != 2)
        !           467:                                return (-1);
        !           468:                        bcopy(&ko, o, sizeof(*o));
        !           469:                        errstr = NULL;
        !           470:                } else {
        !           471:                        o->bo_id[o->bo_n++] =
        !           472:                            strtonum(sp, 0, UINT_MAX, &errstr);
        !           473:                }
        !           474:                if (errstr || o->bo_n > BER_MAX_OID_LEN)
        !           475:                        return (-1);
        !           476:        }
        !           477:
        !           478:        return (0);
        !           479: }
        !           480:
        !           481: unsigned int
        !           482: smi_application(struct ber_element *elm)
        !           483: {
        !           484:        if (elm->be_class != BER_CLASS_APPLICATION)
        !           485:                return (BER_TYPE_OCTETSTRING);
        !           486:
        !           487:        switch (elm->be_type) {
        !           488:        case SNMP_T_IPADDR:
        !           489:                return (BER_TYPE_OCTETSTRING);
        !           490:        case SNMP_T_COUNTER32:
        !           491:        case SNMP_T_GAUGE32:
        !           492:        case SNMP_T_TIMETICKS:
        !           493:        case SNMP_T_OPAQUE:
        !           494:        case SNMP_T_COUNTER64:
        !           495:                return (BER_TYPE_INTEGER);
        !           496:        default:
        !           497:                break;
        !           498:        }
        !           499:        return (BER_TYPE_OCTETSTRING);
        !           500:
        !           501: }
        !           502:
        !           503: char *
        !           504: smi_oid2string(struct ber_oid *o, char *buf, size_t len,
        !           505:     enum smi_oid_lookup lookup)
        !           506: {
        !           507:        char             str[256];
        !           508:        struct oid      *value, key;
        !           509:        size_t           i;
        !           510:
        !           511:        bzero(buf, len);
        !           512:        bzero(&key, sizeof(key));
        !           513:        bcopy(o, &key.o_id, sizeof(struct ber_oid));
        !           514:        key.o_flags |= OID_KEY;         /* do not match wildcards */
        !           515:
        !           516:        for (i = 0; i < o->bo_n; i++) {
        !           517:                key.o_oidlen = i + 1;
        !           518:                if (lookup != smi_oidl_numeric &&
        !           519:                    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) {
        !           520:                        snprintf(str, sizeof(str), "%s", value->o_name);
        !           521:                        if (lookup == smi_oidl_short && i + 1 < o->bo_n) {
        !           522:                                key.o_oidlen = i + 2;
        !           523:                                if (RB_FIND(oidtree, &smi_oidtree, &key) != NULL)
        !           524:                                        continue;
        !           525:                        }
        !           526:                } else
        !           527:                        snprintf(str, sizeof(str), "%d", key.o_oid[i]);
        !           528:                if (*buf != '\0' || i == 0)
        !           529:                        strlcat(buf, ".", len);
        !           530:                strlcat(buf, str, len);
        !           531:        }
        !           532:
        !           533:        return (buf);
        !           534: }
        !           535:
        !           536: void
        !           537: smi_mibtree(struct oid *oids)
        !           538: {
        !           539:        struct oid      *oid, *decl;
        !           540:        size_t           i;
        !           541:
        !           542:        for (i = 0; oids[i].o_oid[0] != 0; i++) {
        !           543:                oid = &oids[i];
        !           544:                if (oid->o_name != NULL) {
        !           545:                        RB_INSERT(oidtree, &smi_oidtree, oid);
        !           546:                        RB_INSERT(keytree, &smi_keytree, oid);
        !           547:                        continue;
        !           548:                }
        !           549:                decl = RB_FIND(oidtree, &smi_oidtree, oid);
        !           550:                decl->o_flags = oid->o_flags;
        !           551:                decl->o_get = oid->o_get;
        !           552:                decl->o_set = oid->o_set;
        !           553:                decl->o_table = oid->o_table;
        !           554:                decl->o_val = oid->o_val;
        !           555:                decl->o_data = oid->o_data;
        !           556:        }
        !           557: }
        !           558:
        !           559: struct oid *
        !           560: smi_findkey(char *name)
        !           561: {
        !           562:        struct oid      oid;
        !           563:        if (name == NULL)
        !           564:                return (NULL);
        !           565:        oid.o_name = name;
        !           566:        return (RB_FIND(keytree, &smi_keytree, &oid));
        !           567: }
        !           568:
        !           569: struct oid *
        !           570: smi_foreach(struct oid *oid, u_int flags)
        !           571: {
        !           572:        /*
        !           573:         * Traverse the tree of MIBs with the option to check
        !           574:         * for specific OID flags.
        !           575:         */
        !           576:        if (oid == NULL) {
        !           577:                oid = RB_MIN(oidtree, &smi_oidtree);
        !           578:                if (oid == NULL)
        !           579:                        return (NULL);
        !           580:                if (flags == 0 || (oid->o_flags & flags))
        !           581:                        return (oid);
        !           582:        }
        !           583:        for (;;) {
        !           584:                oid = RB_NEXT(oidtree, &smi_oidtree, oid);
        !           585:                if (oid == NULL)
        !           586:                        break;
        !           587:                if (flags == 0 || (oid->o_flags & flags))
        !           588:                        return (oid);
        !           589:        }
        !           590:
        !           591:        return (oid);
        !           592: }
        !           593:
        !           594: int
        !           595: smi_oid_cmp(struct oid *a, struct oid *b)
        !           596: {
        !           597:        size_t   i;
        !           598:
        !           599:        for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++) {
        !           600:                if (a->o_oid[i] != b->o_oid[i])
        !           601:                        return (a->o_oid[i] - b->o_oid[i]);
        !           602:        }
        !           603:
        !           604:        /*
        !           605:         * Return success if the matched object is a table
        !           606:         * or a MIB registered by a subagent
        !           607:         * (it will match any sub-elements)
        !           608:         */
        !           609:        if ((b->o_flags & OID_TABLE ||
        !           610:            b->o_flags & OID_REGISTERED) &&
        !           611:            (a->o_flags & OID_KEY) == 0 &&
        !           612:            (a->o_oidlen > b->o_oidlen))
        !           613:                return (0);
        !           614:
        !           615:        return (a->o_oidlen - b->o_oidlen);
        !           616: }
        !           617:
        !           618: int
        !           619: smi_key_cmp(struct oid *a, struct oid *b)
        !           620: {
        !           621:        if (a->o_name == NULL || b->o_name == NULL)
        !           622:                return (-1);
        !           623:        return (strcasecmp(a->o_name, b->o_name));
        !           624: }
        !           625:
        !           626: RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp)
        !           627: RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp)