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

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