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

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