[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.2

1.2     ! deraadt     1: /*     $OpenBSD: smi.c,v 1.1 2019/08/09 06:17:59 martijn Exp $ */
1.1       martijn     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");
1.2     ! deraadt   371:                } else {
1.1       martijn   372:                        for (i = 0; i < root->be_len; i++) {
                    373:                                if (!isprint(buf[i])) {
                    374:                                        if (output_string == smi_os_default)
                    375:                                                output_string = smi_os_hex;
                    376:                                        else if (output_string == smi_os_ascii)
                    377:                                                is_hex = 1;
                    378:                                        break;
                    379:                                }
                    380:                        }
                    381:                        /*
                    382:                         * hex is 3 * n (2 digits + n - 1 spaces + NUL-byte)
                    383:                         * ascii can be max (2 * n) + 2 quotes + NUL-byte
                    384:                         */
                    385:                        if ((p = str = reallocarray(NULL,
                    386:                            output_string == smi_os_hex ? 3 : 2,
                    387:                            root->be_len + 2)) == NULL)
                    388:                                goto fail;
                    389:                        if (is_hex)
                    390:                                *str++ = '"';
                    391:                        for (i = 0; i < root->be_len; i++) {
                    392:                                switch (output_string) {
                    393:                                case smi_os_default:
                    394:                                        /* FALLTHROUGH */
                    395:                                case smi_os_ascii:
                    396:                                        /*
                    397:                                         * There's probably more edgecases here,
                    398:                                         * not fully investigated
                    399:                                         */
                    400:                                        if (is_hex && buf[i] == '\\')
                    401:                                                *str++ = '\\';
                    402:                                        *str++ = isprint(buf[i]) ? buf[i] : '.';
                    403:                                        break;
                    404:                                case smi_os_hex:
                    405:                                        sprintf(str, "%s%02hhX",
                    406:                                            i == 0 ? "" :
                    407:                                            i % 16 == 0 ? "\n" : " ", buf[i]);
                    408:                                        str += i == 0 ? 2 : 3;
                    409:                                        break;
                    410:                                }
                    411:                        }
                    412:                        if (is_hex)
                    413:                                *str++ = '"';
                    414:                        *str = '\0';
                    415:                        str = NULL;
                    416:                        if (asprintf(&str, "%s%s",
                    417:                            print_hint ?
                    418:                            output_string == smi_os_hex ? "Hex-STRING: " :
                    419:                            "STRING: " :
                    420:                            "", p) == -1) {
                    421:                                free(p);
                    422:                                goto fail;
                    423:                        }
                    424:                        free(p);
                    425:                }
                    426:                break;
                    427:        case BER_TYPE_NULL:     /* no payload */
                    428:        case BER_TYPE_EOC:
                    429:        case BER_TYPE_SEQUENCE:
                    430:        case BER_TYPE_SET:
                    431:        default:
                    432:                str = strdup("");
                    433:                break;
                    434:        }
                    435:
                    436:        return (str);
                    437:
                    438:  fail:
                    439:        free(str);
                    440:        return (NULL);
                    441: }
                    442:
                    443: int
                    444: smi_string2oid(const char *oidstr, struct ber_oid *o)
                    445: {
                    446:        char                    *sp, *p, str[BUFSIZ];
                    447:        const char              *errstr;
                    448:        struct oid              *oid;
                    449:        struct ber_oid           ko;
                    450:
                    451:        if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
                    452:                return (-1);
                    453:        bzero(o, sizeof(*o));
                    454:
                    455:        /*
                    456:         * Parse OID strings in the common form n.n.n or n-n-n.
                    457:         * Based on ber_string2oid with additional support for symbolic names.
                    458:         */
                    459:        p = sp = str[0] == '.' ? str + 1 : str;
                    460:        for (; p != NULL; sp = p) {
                    461:                if ((p = strpbrk(p, ".-")) != NULL)
                    462:                        *p++ = '\0';
                    463:                if ((oid = smi_findkey(sp)) != NULL) {
                    464:                        bcopy(&oid->o_id, &ko, sizeof(ko));
                    465:                        if (o->bo_n && ber_oid_cmp(o, &ko) != 2)
                    466:                                return (-1);
                    467:                        bcopy(&ko, o, sizeof(*o));
                    468:                        errstr = NULL;
                    469:                } else {
                    470:                        o->bo_id[o->bo_n++] =
                    471:                            strtonum(sp, 0, UINT_MAX, &errstr);
                    472:                }
                    473:                if (errstr || o->bo_n > BER_MAX_OID_LEN)
                    474:                        return (-1);
                    475:        }
                    476:
                    477:        return (0);
                    478: }
                    479:
                    480: unsigned int
                    481: smi_application(struct ber_element *elm)
                    482: {
                    483:        if (elm->be_class != BER_CLASS_APPLICATION)
                    484:                return (BER_TYPE_OCTETSTRING);
                    485:
                    486:        switch (elm->be_type) {
                    487:        case SNMP_T_IPADDR:
                    488:                return (BER_TYPE_OCTETSTRING);
                    489:        case SNMP_T_COUNTER32:
                    490:        case SNMP_T_GAUGE32:
                    491:        case SNMP_T_TIMETICKS:
                    492:        case SNMP_T_OPAQUE:
                    493:        case SNMP_T_COUNTER64:
                    494:                return (BER_TYPE_INTEGER);
                    495:        default:
                    496:                break;
                    497:        }
                    498:        return (BER_TYPE_OCTETSTRING);
                    499:
                    500: }
                    501:
                    502: char *
                    503: smi_oid2string(struct ber_oid *o, char *buf, size_t len,
                    504:     enum smi_oid_lookup lookup)
                    505: {
                    506:        char             str[256];
                    507:        struct oid      *value, key;
                    508:        size_t           i;
                    509:
                    510:        bzero(buf, len);
                    511:        bzero(&key, sizeof(key));
                    512:        bcopy(o, &key.o_id, sizeof(struct ber_oid));
                    513:        key.o_flags |= OID_KEY;         /* do not match wildcards */
                    514:
                    515:        for (i = 0; i < o->bo_n; i++) {
                    516:                key.o_oidlen = i + 1;
                    517:                if (lookup != smi_oidl_numeric &&
                    518:                    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) {
                    519:                        snprintf(str, sizeof(str), "%s", value->o_name);
                    520:                        if (lookup == smi_oidl_short && i + 1 < o->bo_n) {
                    521:                                key.o_oidlen = i + 2;
                    522:                                if (RB_FIND(oidtree, &smi_oidtree, &key) != NULL)
                    523:                                        continue;
                    524:                        }
                    525:                } else
                    526:                        snprintf(str, sizeof(str), "%d", key.o_oid[i]);
                    527:                if (*buf != '\0' || i == 0)
                    528:                        strlcat(buf, ".", len);
                    529:                strlcat(buf, str, len);
                    530:        }
                    531:
                    532:        return (buf);
                    533: }
                    534:
                    535: void
                    536: smi_mibtree(struct oid *oids)
                    537: {
                    538:        struct oid      *oid, *decl;
                    539:        size_t           i;
                    540:
                    541:        for (i = 0; oids[i].o_oid[0] != 0; i++) {
                    542:                oid = &oids[i];
                    543:                if (oid->o_name != NULL) {
                    544:                        RB_INSERT(oidtree, &smi_oidtree, oid);
                    545:                        RB_INSERT(keytree, &smi_keytree, oid);
                    546:                        continue;
                    547:                }
                    548:                decl = RB_FIND(oidtree, &smi_oidtree, oid);
                    549:                decl->o_flags = oid->o_flags;
                    550:                decl->o_get = oid->o_get;
                    551:                decl->o_set = oid->o_set;
                    552:                decl->o_table = oid->o_table;
                    553:                decl->o_val = oid->o_val;
                    554:                decl->o_data = oid->o_data;
                    555:        }
                    556: }
                    557:
                    558: struct oid *
                    559: smi_findkey(char *name)
                    560: {
                    561:        struct oid      oid;
                    562:        if (name == NULL)
                    563:                return (NULL);
                    564:        oid.o_name = name;
                    565:        return (RB_FIND(keytree, &smi_keytree, &oid));
                    566: }
                    567:
                    568: struct oid *
                    569: smi_foreach(struct oid *oid, u_int flags)
                    570: {
                    571:        /*
                    572:         * Traverse the tree of MIBs with the option to check
                    573:         * for specific OID flags.
                    574:         */
                    575:        if (oid == NULL) {
                    576:                oid = RB_MIN(oidtree, &smi_oidtree);
                    577:                if (oid == NULL)
                    578:                        return (NULL);
                    579:                if (flags == 0 || (oid->o_flags & flags))
                    580:                        return (oid);
                    581:        }
                    582:        for (;;) {
                    583:                oid = RB_NEXT(oidtree, &smi_oidtree, oid);
                    584:                if (oid == NULL)
                    585:                        break;
                    586:                if (flags == 0 || (oid->o_flags & flags))
                    587:                        return (oid);
                    588:        }
                    589:
                    590:        return (oid);
                    591: }
                    592:
                    593: int
                    594: smi_oid_cmp(struct oid *a, struct oid *b)
                    595: {
                    596:        size_t   i;
                    597:
                    598:        for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++) {
                    599:                if (a->o_oid[i] != b->o_oid[i])
                    600:                        return (a->o_oid[i] - b->o_oid[i]);
                    601:        }
                    602:
                    603:        /*
                    604:         * Return success if the matched object is a table
                    605:         * or a MIB registered by a subagent
                    606:         * (it will match any sub-elements)
                    607:         */
                    608:        if ((b->o_flags & OID_TABLE ||
                    609:            b->o_flags & OID_REGISTERED) &&
                    610:            (a->o_flags & OID_KEY) == 0 &&
                    611:            (a->o_oidlen > b->o_oidlen))
                    612:                return (0);
                    613:
                    614:        return (a->o_oidlen - b->o_oidlen);
                    615: }
                    616:
                    617: int
                    618: smi_key_cmp(struct oid *a, struct oid *b)
                    619: {
                    620:        if (a->o_name == NULL || b->o_name == NULL)
                    621:                return (-1);
                    622:        return (strcasecmp(a->o_name, b->o_name));
                    623: }
                    624:
                    625: RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp)
                    626: RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp)