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

1.3     ! deraadt     1: /*     $OpenBSD: smi.c,v 1.2 2019/08/11 14:41:20 deraadt 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:
1.3     ! deraadt   184:        if ((value = smi_print_element(root, 1, smi_os_default,
        !           185:            smi_oidl_numeric)) == NULL)
1.1       martijn   186:                goto invalid;
                    187:
                    188:        switch (root->be_encoding) {
                    189:        case BER_TYPE_BOOLEAN:
                    190:                fprintf(stderr, "%s", value);
                    191:                break;
                    192:        case BER_TYPE_INTEGER:
                    193:        case BER_TYPE_ENUMERATED:
                    194:                fprintf(stderr, "value %s", value);
                    195:                break;
                    196:        case BER_TYPE_BITSTRING:
                    197:                fprintf(stderr, "hexdump %s", value);
                    198:                break;
                    199:        case BER_TYPE_OBJECT:
                    200:                fprintf(stderr, "oid %s", value);
                    201:                break;
                    202:        case BER_TYPE_OCTETSTRING:
                    203:                if (root->be_class == BER_CLASS_APPLICATION &&
                    204:                    root->be_type == SNMP_T_IPADDR) {
                    205:                        fprintf(stderr, "addr %s", value);
                    206:                } else {
                    207:                        fprintf(stderr, "string %s", value);
                    208:                }
                    209:                break;
                    210:        case BER_TYPE_NULL:     /* no payload */
                    211:        case BER_TYPE_EOC:
                    212:        case BER_TYPE_SEQUENCE:
                    213:        case BER_TYPE_SET:
                    214:        default:
                    215:                fprintf(stderr, "%s", value);
                    216:                break;
                    217:        }
                    218:
                    219:  invalid:
                    220:        if (value == NULL)
                    221:                fprintf(stderr, "<INVALID>");
                    222:        else
                    223:                free(value);
                    224:        fprintf(stderr, "\n");
                    225:
                    226:        if (constructed)
                    227:                root->be_encoding = constructed;
                    228:
                    229:        if (constructed && root->be_sub) {
                    230:                indent += 2;
                    231:                smi_debug_elements(root->be_sub);
                    232:                indent -= 2;
                    233:        }
                    234:        if (root->be_next)
                    235:                smi_debug_elements(root->be_next);
                    236: }
                    237:
                    238: char *
                    239: smi_print_element(struct ber_element *root, int print_hint,
                    240:     enum smi_output_string output_string, enum smi_oid_lookup lookup)
                    241: {
                    242:        char            *str = NULL, *buf, *p;
                    243:        size_t           len, i;
                    244:        long long        v, ticks;
                    245:        int              d;
                    246:        int              is_hex = 0;
                    247:        struct ber_oid   o;
                    248:        char             strbuf[BUFSIZ];
                    249:        char            *hint;
                    250:        int              days, hours, min, sec, csec;
                    251:
                    252:        switch (root->be_encoding) {
                    253:        case BER_TYPE_BOOLEAN:
                    254:                if (ber_get_boolean(root, &d) == -1)
                    255:                        goto fail;
                    256:                if (print_hint) {
                    257:                        if (asprintf(&str, "INTEGER: %s(%d)",
                    258:                            d ? "true" : "false", d) == -1)
                    259:                                goto fail;
1.3     ! deraadt   260:                } else
1.1       martijn   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:                }
1.3     ! deraadt   332:                if (asprintf(&str, "%s%lld", print_hint ? hint : "", v) == -1)
1.1       martijn   333:                        goto fail;
                    334:                break;
                    335:        case BER_TYPE_BITSTRING:
                    336:                if (ber_get_bitstring(root, (void *)&buf, &len) == -1)
                    337:                        goto fail;
                    338:                if ((str = calloc(1, len * 2 + 1 + sizeof("BITS: "))) == NULL)
                    339:                        goto fail;
                    340:                p = str;
                    341:                if (print_hint) {
                    342:                        strlcpy(str, "BITS: ", sizeof(str));
                    343:                        p += sizeof("BITS: ");
                    344:                }
                    345:                for (i = 0; i < len; i++) {
                    346:                        snprintf(p, 3, "%02x", buf[i]);
                    347:                        p += 2;
                    348:                }
                    349:                break;
                    350:        case BER_TYPE_OBJECT:
                    351:                if (ber_get_oid(root, &o) == -1)
                    352:                        goto fail;
                    353:                if (asprintf(&str, "%s%s",
                    354:                    print_hint ? "OID: " : "",
                    355:                    smi_oid2string(&o, strbuf, sizeof(strbuf), lookup)) == -1)
                    356:                        goto fail;
                    357:                break;
                    358:        case BER_TYPE_OCTETSTRING:
                    359:                if (ber_get_string(root, &buf) == -1)
                    360:                        goto fail;
                    361:                if (root->be_class == BER_CLASS_APPLICATION &&
                    362:                    root->be_type == SNMP_T_IPADDR) {
                    363:                        if (asprintf(&str, "%s%s",
                    364:                            print_hint ? "IpAddress: " : "",
                    365:                            inet_ntoa(*(struct in_addr *)buf)) == -1)
                    366:                                goto fail;
                    367:                } else if (root->be_class == BER_CLASS_CONTEXT &&
                    368:                    root->be_type == BER_TYPE_EOC) {
                    369:                        str = strdup("No Such Object available on this agent at this OID");
1.2       deraadt   370:                } else {
1.1       martijn   371:                        for (i = 0; i < root->be_len; i++) {
                    372:                                if (!isprint(buf[i])) {
                    373:                                        if (output_string == smi_os_default)
                    374:                                                output_string = smi_os_hex;
                    375:                                        else if (output_string == smi_os_ascii)
                    376:                                                is_hex = 1;
                    377:                                        break;
                    378:                                }
                    379:                        }
                    380:                        /*
                    381:                         * hex is 3 * n (2 digits + n - 1 spaces + NUL-byte)
                    382:                         * ascii can be max (2 * n) + 2 quotes + NUL-byte
                    383:                         */
                    384:                        if ((p = str = reallocarray(NULL,
                    385:                            output_string == smi_os_hex ? 3 : 2,
                    386:                            root->be_len + 2)) == NULL)
                    387:                                goto fail;
                    388:                        if (is_hex)
                    389:                                *str++ = '"';
                    390:                        for (i = 0; i < root->be_len; i++) {
                    391:                                switch (output_string) {
                    392:                                case smi_os_default:
                    393:                                        /* FALLTHROUGH */
                    394:                                case smi_os_ascii:
                    395:                                        /*
                    396:                                         * There's probably more edgecases here,
                    397:                                         * not fully investigated
                    398:                                         */
                    399:                                        if (is_hex && buf[i] == '\\')
                    400:                                                *str++ = '\\';
                    401:                                        *str++ = isprint(buf[i]) ? buf[i] : '.';
                    402:                                        break;
                    403:                                case smi_os_hex:
                    404:                                        sprintf(str, "%s%02hhX",
                    405:                                            i == 0 ? "" :
                    406:                                            i % 16 == 0 ? "\n" : " ", buf[i]);
                    407:                                        str += i == 0 ? 2 : 3;
                    408:                                        break;
                    409:                                }
                    410:                        }
                    411:                        if (is_hex)
                    412:                                *str++ = '"';
                    413:                        *str = '\0';
                    414:                        str = NULL;
                    415:                        if (asprintf(&str, "%s%s",
                    416:                            print_hint ?
                    417:                            output_string == smi_os_hex ? "Hex-STRING: " :
                    418:                            "STRING: " :
                    419:                            "", p) == -1) {
                    420:                                free(p);
                    421:                                goto fail;
                    422:                        }
                    423:                        free(p);
                    424:                }
                    425:                break;
                    426:        case BER_TYPE_NULL:     /* no payload */
                    427:        case BER_TYPE_EOC:
                    428:        case BER_TYPE_SEQUENCE:
                    429:        case BER_TYPE_SET:
                    430:        default:
                    431:                str = strdup("");
                    432:                break;
                    433:        }
                    434:
                    435:        return (str);
                    436:
                    437:  fail:
                    438:        free(str);
                    439:        return (NULL);
                    440: }
                    441:
                    442: int
                    443: smi_string2oid(const char *oidstr, struct ber_oid *o)
                    444: {
                    445:        char                    *sp, *p, str[BUFSIZ];
                    446:        const char              *errstr;
                    447:        struct oid              *oid;
                    448:        struct ber_oid           ko;
                    449:
                    450:        if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
                    451:                return (-1);
                    452:        bzero(o, sizeof(*o));
                    453:
                    454:        /*
                    455:         * Parse OID strings in the common form n.n.n or n-n-n.
                    456:         * Based on ber_string2oid with additional support for symbolic names.
                    457:         */
                    458:        p = sp = str[0] == '.' ? str + 1 : str;
                    459:        for (; p != NULL; sp = p) {
                    460:                if ((p = strpbrk(p, ".-")) != NULL)
                    461:                        *p++ = '\0';
                    462:                if ((oid = smi_findkey(sp)) != NULL) {
                    463:                        bcopy(&oid->o_id, &ko, sizeof(ko));
                    464:                        if (o->bo_n && ber_oid_cmp(o, &ko) != 2)
                    465:                                return (-1);
                    466:                        bcopy(&ko, o, sizeof(*o));
                    467:                        errstr = NULL;
                    468:                } else {
                    469:                        o->bo_id[o->bo_n++] =
                    470:                            strtonum(sp, 0, UINT_MAX, &errstr);
                    471:                }
                    472:                if (errstr || o->bo_n > BER_MAX_OID_LEN)
                    473:                        return (-1);
                    474:        }
                    475:
                    476:        return (0);
                    477: }
                    478:
                    479: unsigned int
                    480: smi_application(struct ber_element *elm)
                    481: {
                    482:        if (elm->be_class != BER_CLASS_APPLICATION)
                    483:                return (BER_TYPE_OCTETSTRING);
                    484:
                    485:        switch (elm->be_type) {
                    486:        case SNMP_T_IPADDR:
                    487:                return (BER_TYPE_OCTETSTRING);
                    488:        case SNMP_T_COUNTER32:
                    489:        case SNMP_T_GAUGE32:
                    490:        case SNMP_T_TIMETICKS:
                    491:        case SNMP_T_OPAQUE:
                    492:        case SNMP_T_COUNTER64:
                    493:                return (BER_TYPE_INTEGER);
                    494:        default:
                    495:                break;
                    496:        }
                    497:        return (BER_TYPE_OCTETSTRING);
                    498:
                    499: }
                    500:
                    501: char *
                    502: smi_oid2string(struct ber_oid *o, char *buf, size_t len,
                    503:     enum smi_oid_lookup lookup)
                    504: {
                    505:        char             str[256];
                    506:        struct oid      *value, key;
                    507:        size_t           i;
                    508:
                    509:        bzero(buf, len);
                    510:        bzero(&key, sizeof(key));
                    511:        bcopy(o, &key.o_id, sizeof(struct ber_oid));
                    512:        key.o_flags |= OID_KEY;         /* do not match wildcards */
                    513:
                    514:        for (i = 0; i < o->bo_n; i++) {
                    515:                key.o_oidlen = i + 1;
                    516:                if (lookup != smi_oidl_numeric &&
                    517:                    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) {
                    518:                        snprintf(str, sizeof(str), "%s", value->o_name);
                    519:                        if (lookup == smi_oidl_short && i + 1 < o->bo_n) {
                    520:                                key.o_oidlen = i + 2;
                    521:                                if (RB_FIND(oidtree, &smi_oidtree, &key) != NULL)
                    522:                                        continue;
                    523:                        }
                    524:                } else
                    525:                        snprintf(str, sizeof(str), "%d", key.o_oid[i]);
                    526:                if (*buf != '\0' || i == 0)
                    527:                        strlcat(buf, ".", len);
                    528:                strlcat(buf, str, len);
                    529:        }
                    530:
                    531:        return (buf);
                    532: }
                    533:
                    534: void
                    535: smi_mibtree(struct oid *oids)
                    536: {
                    537:        struct oid      *oid, *decl;
                    538:        size_t           i;
                    539:
                    540:        for (i = 0; oids[i].o_oid[0] != 0; i++) {
                    541:                oid = &oids[i];
                    542:                if (oid->o_name != NULL) {
                    543:                        RB_INSERT(oidtree, &smi_oidtree, oid);
                    544:                        RB_INSERT(keytree, &smi_keytree, oid);
                    545:                        continue;
                    546:                }
                    547:                decl = RB_FIND(oidtree, &smi_oidtree, oid);
                    548:                decl->o_flags = oid->o_flags;
                    549:                decl->o_get = oid->o_get;
                    550:                decl->o_set = oid->o_set;
                    551:                decl->o_table = oid->o_table;
                    552:                decl->o_val = oid->o_val;
                    553:                decl->o_data = oid->o_data;
                    554:        }
                    555: }
                    556:
                    557: struct oid *
                    558: smi_findkey(char *name)
                    559: {
                    560:        struct oid      oid;
                    561:        if (name == NULL)
                    562:                return (NULL);
                    563:        oid.o_name = name;
                    564:        return (RB_FIND(keytree, &smi_keytree, &oid));
                    565: }
                    566:
                    567: struct oid *
                    568: smi_foreach(struct oid *oid, u_int flags)
                    569: {
                    570:        /*
                    571:         * Traverse the tree of MIBs with the option to check
                    572:         * for specific OID flags.
                    573:         */
                    574:        if (oid == NULL) {
                    575:                oid = RB_MIN(oidtree, &smi_oidtree);
                    576:                if (oid == NULL)
                    577:                        return (NULL);
                    578:                if (flags == 0 || (oid->o_flags & flags))
                    579:                        return (oid);
                    580:        }
                    581:        for (;;) {
                    582:                oid = RB_NEXT(oidtree, &smi_oidtree, oid);
                    583:                if (oid == NULL)
                    584:                        break;
                    585:                if (flags == 0 || (oid->o_flags & flags))
                    586:                        return (oid);
                    587:        }
                    588:
                    589:        return (oid);
                    590: }
                    591:
                    592: int
                    593: smi_oid_cmp(struct oid *a, struct oid *b)
                    594: {
                    595:        size_t   i;
                    596:
                    597:        for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++) {
                    598:                if (a->o_oid[i] != b->o_oid[i])
                    599:                        return (a->o_oid[i] - b->o_oid[i]);
                    600:        }
                    601:
                    602:        /*
                    603:         * Return success if the matched object is a table
                    604:         * or a MIB registered by a subagent
                    605:         * (it will match any sub-elements)
                    606:         */
                    607:        if ((b->o_flags & OID_TABLE ||
                    608:            b->o_flags & OID_REGISTERED) &&
                    609:            (a->o_flags & OID_KEY) == 0 &&
                    610:            (a->o_oidlen > b->o_oidlen))
                    611:                return (0);
                    612:
                    613:        return (a->o_oidlen - b->o_oidlen);
                    614: }
                    615:
                    616: int
                    617: smi_key_cmp(struct oid *a, struct oid *b)
                    618: {
                    619:        if (a->o_name == NULL || b->o_name == NULL)
                    620:                return (-1);
                    621:        return (strcasecmp(a->o_name, b->o_name));
                    622: }
                    623:
                    624: RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp)
                    625: RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp)