Annotation of 43BSDReno/contrib/isode-beta/doc/rfcs/smux-api.txt, revision 1.1.1.1

1.1       root        1: 
                      2: 
                      3: 
                      4: 
                      5:           draft            Exporting MIBs for BSD UNIX          May 1990
                      6: 
                      7: 
                      8:                             How to export a MIB module
                      9:                               from a BSD UNIX daemon
                     10:                           using the 4BSD/ISODE SMUX API
                     11: 
                     12:                              Sun May 13 14:54:13 1990
                     13: 
                     14: 
                     15:                                  Marshall T. Rose
                     16: 
                     17:                      Performance Systems International, Inc.
                     18:                             11800 Sunrise Valley Drive
                     19:                                     Suite 1100
                     20:                                 Reston, VA  22091
                     21: 
                     22:                                   [email protected]
                     23: 
                     24: 
                     25: 
                     26: 
                     27: 
                     28: 
                     29:           1.  Status of this Memo
                     30: 
                     31:           This document defines an API for UNIX daemons wishing to
                     32:           implement a MIB module on a BSD UNIX system using the
                     33:           4BSD/ISODE SNMP software.  This is a local mechanism.
                     34: 
                     35: 
                     36: 
                     37: 
                     38: 
                     39: 
                     40: 
                     41: 
                     42: 
                     43: 
                     44: 
                     45: 
                     46: 
                     47: 
                     48: 
                     49: 
                     50: 
                     51: 
                     52: 
                     53: 
                     54: 
                     55: 
                     56: 
                     57: 
                     58:           M.T. Rose                                             [Page 1]
                     59: 
                     60: 
                     61: 
                     62: 
                     63: 
                     64:           draft            Exporting MIBs for BSD UNIX          May 1990
                     65: 
                     66: 
                     67:           2.  The Environment
                     68: 
                     69:           This document gives an overview of how one modifies a UNIX
                     70:           program to export a MIB module to the local SNMP agent.
                     71: 
                     72:           All of the files necessary to interface to the SNMP agent is
                     73:           contained in the ISODE source tree, in the snmp/ directory.
                     74:           Since this document avoids giving the actual C procedural
                     75:           definitions, you should familiarize yourself with the lint
                     76:           library, llib-lisnmp.
                     77: 
                     78:           For the purposes of example, throughout this document we will
                     79:           reference a simple UNIX daemon, unixd, which implements a MIB
                     80:           module for "mbuf statistics".
                     81: 
                     82: 
                     83:           2.1.  The ISODE
                     84: 
                     85:           As you might have guessed, this document assumes that you're
                     86:           running the ISODE on your system.  You should read the READ-ME
                     87:           file at the base of the source tree for instructions on how to
                     88:           configure, generate, and install the ISODE.  In the future, an
                     89:           abbreviated set of instructions, for those interested in
                     90:           running the only 4BSD/ISODE SNMP software, will be written.
                     91: 
                     92:           For now, follow the READ-ME, generate the base system and
                     93:           SNMP, e.g.,
                     94: 
                     95:                % ./make all all-snmp
                     96: 
                     97:           and then install only the 4BSD/ISODE SNMP software:
                     98: 
                     99:                # ./make inst-all inst-snmp
                    100: 
                    101:           However, be sure to read the entire READ-ME file, as there are
                    102:           other steps involved in installing the SNMP software.
                    103: 
                    104: 
                    105: 
                    106: 
                    107: 
                    108: 
                    109: 
                    110: 
                    111: 
                    112: 
                    113: 
                    114: 
                    115: 
                    116: 
                    117:           M.T. Rose                                             [Page 2]
                    118: 
                    119: 
                    120: 
                    121: 
                    122: 
                    123:           draft            Exporting MIBs for BSD UNIX          May 1990
                    124: 
                    125: 
                    126:           3.  MIB Modules
                    127: 
                    128:           The first thing you need to do is to define the actual managed
                    129:           objects which your program will implement.  This is done by
                    130:           writing a "MIB module".  The syntax of the module is defined
                    131:           in the Internet-standard SMI, RFC1155.  It is not the purpose
                    132:           of this document to describe the rules used for writing a MIB
                    133:           module.  However, here are the basics to speed you on your
                    134:           way.
                    135: 
                    136:           The MIB module is defined in a file called module.my, e.g.,
                    137:           unix.my.  In general, there are three kinds of MIB modules:
                    138: 
                    139:           (1)  If you are defining a MIB module for something UNIX
                    140:                specific, it should probably go under the BSD UNIX MIB
                    141:                (contact Marshall Rose or Keith Sklower to get a number
                    142:                under the UNIX enterprise tree).  In this case, the
                    143:                definition might start something like this:
                    144: 
                    145:                     SendMail-MIB { iso org(3) dod(6) internet(1) private(4)
                    146:                                    enterprises(1) unix (4) sendmail (99) }
                    147: 
                    148:                     DEFINITIONS ::= BEGIN
                    149: 
                    150:                     IMPORTS
                    151:                             unix --*, OBJECT-TYPE *--
                    152:                                 FROM RFC1155-SMI;
                    153: 
                    154:                     sendMail OBJECT IDENTIFIER ::= { unix 99 }
                    155: 
                    156: 
                    157:           (2)  If you are defining a MIB module on a multilateral,
                    158:                experimental basis, e.g., for a protocol like the NTP,
                    159:                then you should contact the Internet Assigned Numbers
                    160:                Authority ([email protected]) and ask for an experimental
                    161:                number.  In this case, the definition might start
                    162:                something like this:
                    163: 
                    164:                     FIZBIN-MIB DEFINITIONS ::= BEGIN
                    165: 
                    166:                     IMPORTS
                    167:                             experimental, OBJECT-TYPE
                    168:                                 FROM RFC1155-SMI;
                    169: 
                    170:                     fizBin OBJECT IDENTIFIER ::= { experimental 99 }
                    171: 
                    172: 
                    173: 
                    174: 
                    175: 
                    176:           M.T. Rose                                             [Page 3]
                    177: 
                    178: 
                    179: 
                    180: 
                    181: 
                    182:           draft            Exporting MIBs for BSD UNIX          May 1990
                    183: 
                    184: 
                    185:           (3)  Otherwise, if you are defining a MIB module for something
                    186:                specific to your enterprise, then you contact the
                    187:                Internet Assigned Numbers Authority ([email protected]) and
                    188:                ask for an enterprise number (assuming you don't already
                    189:                have one).  In this case, the definition might start
                    190:                something like this:
                    191: 
                    192:                     FIZZBIN-MIB DEFINITIONS ::= BEGIN
                    193: 
                    194:                     IMPORTS
                    195:                             enterprises, OBJECT-TYPE
                    196:                                 FROM RFC1155-SMI;
                    197: 
                    198:                     cheetah OBJECT IDENTIFIER ::= { enterprises 9999 }
                    199: 
                    200:                     fizBin OBJECT IDENTIFIER ::= { cheetah 1 }
                    201: 
                    202: 
                    203:           Regardless of the kind of MIB module, this last OBJECT
                    204:           IDENTIFIER points to the root of the tree which your agent is
                    205:           going to export.
                    206: 
                    207:           Following this start, you have the actual definitions of the
                    208:           MIB objects, followed by
                    209: 
                    210:                END
                    211: 
                    212: 
                    213: 
                    214:           3.1.  Compiling MIB modules
                    215: 
                    216:           The next step is to compile the MIB module into a form that
                    217:           your program can read.  This is done using the mosy program:
                    218: 
                    219:                % others/mosy/xmosy module.my
                    220: 
                    221:           which will create the file module.defs.  In most cases you
                    222:           will need to prefix this file with definitions from the root
                    223:           of the OBJECT IDENTIFIER tree, e.g.,
                    224: 
                    225:                % cat $(INCDIR)isode/snmp/smi.defs module.defs > daemon.defs
                    226: 
                    227:           where the daemon.defs file will be the one which you install
                    228:           with your program binary.
                    229: 
                    230: 
                    231: 
                    232: 
                    233: 
                    234: 
                    235:           M.T. Rose                                             [Page 4]
                    236: 
                    237: 
                    238: 
                    239: 
                    240: 
                    241:           draft            Exporting MIBs for BSD UNIX          May 1990
                    242: 
                    243: 
                    244:           3.1.1.  The Syntax of compiled MIB modules
                    245: 
                    246:           The syntax is pretty simple:
                    247: 
                    248:           (1)  Comments start with "--" or "#" at the beginning of a
                    249:                line.
                    250: 
                    251:           (2)  Object identifiers are defined like this:
                    252: 
                    253:                     name            value
                    254: 
                    255:                e.g.,
                    256: 
                    257:                     internet        iso.3.6.1
                    258: 
                    259: 
                    260:           (3)  Object types are defined like this:
                    261: 
                    262:                     name      oid       syntax         access     status
                    263: 
                    264:                e.g.,
                    265: 
                    266:                     sysDescr  system.1  DisplayString  read-only  mandatory
                    267: 
                    268:                where "name" and "oid" are fairly obvious.  For the rest:
                    269: 
                    270:                     "syntax" is the name of a defined syntax;
                    271: 
                    272:                     "access" is one of read-only, read-write", or none;
                    273:                     and,
                    274: 
                    275:                     "status" is one of mandatory, optional,
                    276:                     deprecated, or obsolete.
                    277: 
                    278:                Names of objects are always case-sensitive.
                    279: 
                    280: 
                    281: 
                    282: 
                    283: 
                    284: 
                    285: 
                    286: 
                    287: 
                    288: 
                    289: 
                    290: 
                    291: 
                    292: 
                    293: 
                    294:           M.T. Rose                                             [Page 5]
                    295: 
                    296: 
                    297: 
                    298: 
                    299: 
                    300:           draft            Exporting MIBs for BSD UNIX          May 1990
                    301: 
                    302: 
                    303:           4.  SMUX Peers
                    304: 
                    305:           A program which exports a MIB module is termed a "SMUX peer"
                    306:           (SMUX is the name of the protocol used by these programs to
                    307:           communicate with an SNMP agent.)
                    308: 
                    309:           There is a textual database, $(ETCDIR)snmpd.peers, which
                    310:           defines the SMUX peers known to the local SNMP agent.  The
                    311:           syntax of this file is pretty simple:
                    312: 
                    313:           (1)  Comments start with "#" at the beginning of a line.
                    314: 
                    315:           (2)  Each peer is identified in a single line:
                    316: 
                    317:                     name        oid         password    [priority]
                    318: 
                    319:                where "name" and "oid" are fairly obvious.  For the rest:
                    320: 
                    321:                     "password" is a string which the agent will use to
                    322:                     authenticate the SMUX peer;
                    323:                     and,
                    324: 
                    325:                     "priority",
                    326:                     if present,
                    327:                     is the highest priority with which the SMUX peer can register subtrees.
                    328: 
                    329:                The name/oid pairs are assigned by the authority for the
                    330:                BSD UNIX MIB (contact Marshall Rose or Keith Sklower to
                    331:                register the name of your program and get an for your
                    332:                program).
                    333: 
                    334:           Note that this file contains things resembling passwords in
                    335:           the clear.  As such, it should be protected mode 0600 and
                    336:           owned by root.
                    337: 
                    338: 
                    339: 
                    340: 
                    341: 
                    342: 
                    343: 
                    344: 
                    345: 
                    346: 
                    347: 
                    348: 
                    349: 
                    350: 
                    351: 
                    352: 
                    353:           M.T. Rose                                             [Page 6]
                    354: 
                    355: 
                    356: 
                    357: 
                    358: 
                    359:           draft            Exporting MIBs for BSD UNIX          May 1990
                    360: 
                    361: 
                    362:           5.  Daemon Skeleton
                    363: 
                    364:           Now it's time to modify your daemon to export the MIB.  Your
                    365:           source code should include these lines:
                    366: 
                    367:                #include <isode/snmp/smux.h>
                    368:                #include <isode/snmp/objects.h>
                    369:                #include <isode/tailor.h>
                    370: 
                    371:           which will include the definitions for: talking to the SNMP
                    372:           agent via the SMUX protocol, the object management package,
                    373:           and the ISODE tailoring subsystem.
                    374: 
                    375:           When loading your daemon, you should add this to the end of
                    376:           your command to the loader:
                    377: 
                    378:                -lisnmp -lisode
                    379: 
                    380:           which includes the 4BSD/SNMP and ISODE libraries.
                    381: 
                    382:           You should decide if you want to use the ISODE logging
                    383:           subsystem.  This is a convenient mechanism for using a unified
                    384:           logging system.  If you are modifying an already existing
                    385:           daemon, you probably have your own logging package.
                    386:           Otherwise, you should consider using the ISODE subsystem.
                    387: 
                    388: 
                    389:           5.1.  Declarations
                    390: 
                    391:           There are some global variables that your program will have to
                    392:           declare:
                    393: 
                    394:                int     debug = 0;
                    395:                static  char   *myname = "unixd";
                    396: 
                    397:                static LLog     _pgm_log = {
                    398:                    "unixd.log", NULLCP, NULLCP,
                    399:                    LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE,
                    400:                    LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK
                    401:                };
                    402:                static  LLog   *pgm_log = &_pgm_log;
                    403: 
                    404:                static  OID     subtree = NULLOID;
                    405:                static  struct smuxEntry *se = NULL;
                    406: 
                    407: 
                    408: 
                    409: 
                    410: 
                    411: 
                    412:           M.T. Rose                                             [Page 7]
                    413: 
                    414: 
                    415: 
                    416: 
                    417: 
                    418:           draft            Exporting MIBs for BSD UNIX          May 1990
                    419: 
                    420: 
                    421:                static  int     smux_fd = NOTOK;
                    422:                static  int     rock_and_roll = 0;
                    423:                static  int     dont_bother_anymore = 0;
                    424: 
                    425:                static  int     quantum = 0;
                    426: 
                    427:           You only need the definition of _pgm_log and pgm_log if you
                    428:           will be using the ISODE logging subsystem.
                    429: 
                    430: 
                    431:           5.2.  Initialization
                    432: 
                    433:           When your program initializes itself, it should contain some
                    434:           code like this:
                    435: 
                    436:                    if (myname = rindex (argv[0], '/'))
                    437:                        myname++;
                    438:                    if (myname == NULL || *myname == NULL)
                    439:                        myname = argv[0];
                    440: 
                    441:                    isodetailor (myname, 0);
                    442:                    ll_hdinit (pgm_log, myname);
                    443: 
                    444:                /* scan argv, set debug if need be... */
                    445: 
                    446:                    if (debug)
                    447:                        ll_dbinit (pgm_log, myname);
                    448: 
                    449:           Of course, if you're not using the ISODE logging subsystem,
                    450:           you don't have the calls to ll_hdinit or ll_dbinit.
                    451: 
                    452:           After cracking argv, your program should do the usual
                    453:           detaching actions.  Usually at this point, your program reads
                    454:           the compiled MIB module definitions and starts talking to the
                    455:           SNMP agent.
                    456: 
                    457: 
                    458:           5.3.  Reading the compiled MIB module
                    459: 
                    460:           You program should call the readobjects routine to read the
                    461:           module, look-up the subtree which it will export to the SNMP
                    462:           agent, and call the getsmuxEntrybyname routine to find its
                    463:           entry in the snmpd.peers database.  Finally, it should call a
                    464:           routine you define, e.g., init_mib, to initialize it's
                    465:           internal MIB structures.  (We'll look at this routine in
                    466: 
                    467: 
                    468: 
                    469: 
                    470: 
                    471:           M.T. Rose                                             [Page 8]
                    472: 
                    473: 
                    474: 
                    475: 
                    476: 
                    477:           draft            Exporting MIBs for BSD UNIX          May 1990
                    478: 
                    479: 
                    480:           greater detail later on.)
                    481: 
                    482:                    OT      ot;
                    483: 
                    484:                    if (readobjects ("unixd.defs") == NOTOK)
                    485:                        error ("readobjects: %s", PY_pepy);
                    486: 
                    487:                    if ((ot = text2obj ("mbuf")) == NULL)
                    488:                        error ("object
                    489:                    subtree = ot -> ot_name;
                    490: 
                    491:                    if (se = getsmuxEntrybyname ("unixd")) == NULL)
                    492:                        error ("no SMUX entry for
                    493: 
                    494:                    init_mib ();
                    495: 
                    496:           If any of these routines fail, then don't bother trying to
                    497:           export the MIB module.
                    498: 
                    499: 
                    500:           5.4.  Talking to the SNMP agent
                    501: 
                    502:           All of the SMUX routines return NOTOK on failure.  Unless
                    503:           otherwise noted, these routines also return OK on success.  On
                    504:           failure, the variable
                    505: 
                    506:                extern int  smux_errno;
                    507: 
                    508:           is set to a symbolic value defined in smux.h, one of:
                    509: 
                    510:                invalidOperation
                    511:                parameterMissing
                    512:                systemError
                    513:                youLoseBig
                    514:                congestion
                    515:                inProgress
                    516: 
                    517:           In addition, the variable
                    518: 
                    519:                extern char smux_info[BUFSIZ];
                    520: 
                    521:           contains a printable explanation of what happened on failure.
                    522: 
                    523:           All errors are FATAL except for inProgress.  This means retry
                    524:           your operation later on.
                    525: 
                    526: 
                    527: 
                    528: 
                    529: 
                    530:           M.T. Rose                                             [Page 9]
                    531: 
                    532: 
                    533: 
                    534: 
                    535: 
                    536:           draft            Exporting MIBs for BSD UNIX          May 1990
                    537: 
                    538: 
                    539:           5.4.1.  Initialization
                    540: 
                    541:           You program should call the routine smux_init, which
                    542:           initializes a SMUX connection to the local SNMP agent.  This
                    543:           starts a TCP connection, but most likely does not complete it.
                    544:           You program will need to call an open routine (there is only
                    545:           one at present) to finish the connect and establish the SMUX
                    546:           association.
                    547: 
                    548:           If successful, the return value is a file-descriptor, suitable
                    549:           for use with select, etc.
                    550: 
                    551:           On failure, smux_errno will be set to one of congestion,
                    552:           youLoseBig, or systemError.  In this case, you should probably
                    553:           have your program retry the operation every 5 minutes or so.
                    554: 
                    555:                if ((smux_fd = smux_init (debug)) == NOTOK)
                    556:                    error ("smux_init: %s [%s]",
                    557:                           smux_error (smux_errno), smux_info);
                    558:                else
                    559:                    rock_and_roll = 0;
                    560: 
                    561: 
                    562: 
                    563:           5.4.2.  Opening
                    564: 
                    565:           Once smux_init returns OK, you should start selecting for
                    566:           writability on the file-descriptor returned.  Once select says
                    567:           your program can write to the fd, your program should call the
                    568:           routine smux_simple_open, which establishes the SMUX
                    569:           association.
                    570: 
                    571:           On failure, smux_error will be set to one of parameterMissing,
                    572:           invalidOperation, inProgress, systemError, congestion, or
                    573:           youLoseBig.  If the error code is inProgress, then your
                    574:           program should continue retrying the fd for writability, and
                    575:           then call smux_simple_open again.  Otherwise, your program
                    576:           should take the appropriate action based on the error code
                    577:           returned.
                    578: 
                    579:                if (smux_simple_open (&se -> se_identity,
                    580:                                      "SMUX UNIX daemon",
                    581:                                      se -> se_password,
                    582:                                      strlen (se -> se_password))
                    583:                        == NOTOK) {
                    584: 
                    585: 
                    586: 
                    587: 
                    588: 
                    589:           M.T. Rose                                            [Page 10]
                    590: 
                    591: 
                    592: 
                    593: 
                    594: 
                    595:           draft            Exporting MIBs for BSD UNIX          May 1990
                    596: 
                    597: 
                    598:                    if (smux_errno == inProgress)
                    599:                        return;
                    600: 
                    601:                    error ("smux_simple_open: %s [%s]",
                    602:                           smux_error (smux_errno), smux_info);
                    603:                    smux_fd = NOTOK;
                    604:                }
                    605:                else
                    606:                    rock_and_roll = 1;
                    607: 
                    608: 
                    609: 
                    610:           5.4.3.  Closing
                    611: 
                    612:           If, for some reason, your program wishes to close the SMUX
                    613:           association.  There are several reasons that are allowed:
                    614: 
                    615:                goingDown
                    616:                unsupportedVersion
                    617:                packetFormat
                    618:                protocolError
                    619:                internalError
                    620:                authenticationFailure
                    621: 
                    622:           On failure, smux_error will be set to one of invalidOperation,
                    623:           congestion, or youLoseBig.
                    624: 
                    625: 
                    626:           5.4.4.  Registering Subtrees
                    627: 
                    628:           Once smux_simple_open returns OK, your program should register
                    629:           the MIB module that your daemon will export by calling
                    630:           smux_register.  A subtree can be registered in one of three
                    631:           modes:
                    632: 
                    633:                readOnly
                    634:                readWrite
                    635:                delete
                    636: 
                    637:           which are all fairly obvious.
                    638: 
                    639:           Note that a return value of OK from smux_register means only
                    640:           that the registration request was queued for the SNMP agent
                    641:           via the SMUX protocol.  Some time later the SNMP agent's
                    642:           response will be forthcoming.
                    643: 
                    644: 
                    645: 
                    646: 
                    647: 
                    648:           M.T. Rose                                            [Page 11]
                    649: 
                    650: 
                    651: 
                    652: 
                    653: 
                    654:           draft            Exporting MIBs for BSD UNIX          May 1990
                    655: 
                    656: 
                    657:           On failure, smux_error will be set to one of parameterMissing,
                    658:           invalidOperation, congestion, or youLoseBig.  Your program
                    659:           should take the appropriate action based on the error code
                    660:           returned.
                    661: 
                    662:                if (smux_register (subtree, -1, readOnly) == NOTOK) {
                    663:                    error ("smux_register: %s [%s]",
                    664:                            smux_error (smux_errno), smux_info);
                    665:                    smux_fd = NOTOK;
                    666:                }
                    667: 
                    668: 
                    669: 
                    670:           5.4.5.  Main Loop
                    671: 
                    672:           At this point, your program is more or less in it's main loop
                    673:           (actually, it probably entered the main loop after the very
                    674:           first call to smux_init).
                    675: 
                    676:                int     nfds;   /* these are set for other fd's... */
                    677: 
                    678:                fd_set  ifds;
                    679:                fd_set  ofds;
                    680: 
                    681:                    for (;;) {
                    682:                        int     n,
                    683:                                secs;
                    684:                        fd_set  rfds,
                    685:                                wfds;
                    686: 
                    687:                        secs = NOTOK;
                    688: 
                    689:                        rfds = ifds;    /* struct copy */
                    690:                        wfds = ofds;    /*   .. */
                    691: 
                    692:                        if (smux_fd == NOTOK && !dont_bother_anymore)
                    693:                            secs = 5 * 60L;
                    694:                        else
                    695:                            if (rock_and_roll)
                    696:                                FD_SET (smux_fd, &rfds);
                    697:                            else
                    698:                                FD_SET (smux_fd, &wfds);
                    699:                        if (smux_fd >= nfds)
                    700:                            nfds = smux_fd + 1;
                    701: 
                    702: 
                    703: 
                    704: 
                    705: 
                    706: 
                    707:           M.T. Rose                                            [Page 12]
                    708: 
                    709: 
                    710: 
                    711: 
                    712: 
                    713:           draft            Exporting MIBs for BSD UNIX          May 1990
                    714: 
                    715: 
                    716:                        if ((n = xselect (nfds, &rfds, &wfds, NULLFD, secs))
                    717:                                == NOTOK) {
                    718:                            error ("xselect failed");
                    719:                             ...
                    720:                        }
                    721: 
                    722:                /* check fd's for other purposes here... */
                    723: 
                    724:                        if (smux_fd == NOTOK && !dont_bother_anymore) {
                    725:                            if (n == 0) {
                    726:                                if ((smux_fd = smux_init (debug)) == NOTOK)
                    727:                                    error ("smux_init: %s [%s]",
                    728:                                           smux_error (smux_errno),
                    729:                                           smux_info);
                    730:                                else
                    731:                                    rock_and_roll = 0;
                    732:                            }
                    733:                        }
                    734:                        else
                    735:                            if (rock_and_roll) {
                    736:                                if (FD_ISSET (smux_fd, &rfds))
                    737:                                    doit_smux ();
                    738:                            }
                    739:                            else
                    740:                                if (FD_ISSET (smux_fd, &wfds)) {
                    741:                                    if (smux_simple_open (&se -> se_identity,
                    742:                                                  "SMUX UNIX daemon",
                    743:                                                  se -> se_password,
                    744:                                                  strlen (se -> se_password))
                    745:                                            == NOTOK) {
                    746:                                        if (smux_errno != inProgress) {
                    747:                                            error ("smux_simple_open: %s [%s]",
                    748:                                                   smux_error (smux_errno),
                    749:                                                   smux_info);
                    750:                                            smux_fd = NOTOK;
                    751:                                        }
                    752:                                    }
                    753:                                    else {
                    754:                                        rock_and_roll = 1;
                    755: 
                    756:                                        if (smux_register (subtree, -1,
                    757:                                                    readOnly) == NOTOK) {
                    758:                                            error ("smux_register: %s [%s]",
                    759:                                                   smux_error (smux_errno),
                    760:                                                   smux_info);
                    761: 
                    762: 
                    763: 
                    764: 
                    765: 
                    766:           M.T. Rose                                            [Page 13]
                    767: 
                    768: 
                    769: 
                    770: 
                    771: 
                    772:           draft            Exporting MIBs for BSD UNIX          May 1990
                    773: 
                    774: 
                    775:                                            smux_fd = NOTOK;
                    776:                                        }
                    777:                                }
                    778:                    }
                    779: 
                    780:           So, all that remains is to take a look at the routine
                    781:           doit_smux mentioned above.  This is called when select
                    782:           indicates the SMUX file-descriptor is ready for reading.
                    783: 
                    784: 
                    785:           5.4.6.  Events
                    786: 
                    787:           When select indicates the SMUX file-descriptor is ready for
                    788:           reading, your program calls the routine smux_wait to return
                    789:           the next event from the SNMP agent.
                    790: 
                    791:           Note that the event is filled-in from a static area.  On the
                    792:           next call to smux_init, smux_close, or smux_wait, the value
                    793:           will be overwritten.  As such, do not free this structure
                    794:           yourself.
                    795: 
                    796:           On failure, smux_error will be set to one of parameterMissing,
                    797:           invalidOperation, inProgress, or youLoseBig.  Your program
                    798:           should take the appropriate action based on the error code
                    799:           returned.
                    800: 
                    801:                    struct type_SNMP_SMUX__PDUs *event;
                    802: 
                    803:                    if (smux_wait (&event, NOTOK) == NOTOK) {
                    804:                        if (smux_errno == inProgress)
                    805:                            return;
                    806: 
                    807:                        error ("smux_wait: %s [%s]",
                    808:                               smux_error (smux_errno), smux_info);
                    809:                losing: ;
                    810:                        smux_fd = NOTOK;
                    811:                        return;
                    812:                    }
                    813: 
                    814:           Next, your program should switch based on the actual event
                    815:           returned:
                    816: 
                    817:                type_SNMP_SMUX__PDUs_registerResponse
                    818:                type_SNMP_SMUX__PDUs_get_request
                    819:                type_SNMP_SMUX__PDUs_get__next__request
                    820: 
                    821: 
                    822: 
                    823: 
                    824: 
                    825:           M.T. Rose                                            [Page 14]
                    826: 
                    827: 
                    828: 
                    829: 
                    830: 
                    831:           draft            Exporting MIBs for BSD UNIX          May 1990
                    832: 
                    833: 
                    834:                type_SNMP_SMUX__PDUs_close
                    835: 
                    836:           The actual code is fairly straight-forward:
                    837: 
                    838:                switch (event -> offset) {
                    839:                    case type_SNMP_SMUX__PDUs_registerResponse:
                    840:                        {
                    841:                            struct type_SNMP_RRspPDU *rsp =
                    842:                                        event -> un.registerResponse;
                    843: 
                    844:                            if (rsp -> parm == int_SNMP_RRspPDU_failure) {
                    845:                                error ("SMUX registration of %s failed",
                    846:                                       oid2ode (subtree));
                    847:                                dont_bother_anymore = 1;
                    848:                                (void) smux_close (goingDown);
                    849:                                break;
                    850:                            }
                    851:                        }
                    852:                        if (smux_trap (int_SNMP_generic__trap_coldStart,
                    853:                                       0, (struct type_SNMP_VarBindList *) 0)
                    854:                                == NOTOK) {
                    855:                            error ("smux_trap: %s [%s]",
                    856:                                   smux_error (smux_errno), smux_info);
                    857:                            break;
                    858:                        }
                    859:                        return;
                    860: 
                    861:                    case type_SNMP_SMUX__PDUs_get_request:
                    862:                    case type_SNMP_SMUX__PDUs_get__next__request:
                    863:                        get_smux (event -> un.get__request, event -> offset);
                    864:                        return;
                    865: 
                    866:                    case type_SNMP_SMUX__PDUs_close:
                    867:                        notice ("SMUX close: %s",
                    868:                                smux_error (event -> un.close -> parm));
                    869:                        break;
                    870: 
                    871:                    default:
                    872:                        error ("bad SMUX operation: %d", event -> offset);
                    873:                        (void) smux_close (protocolError);
                    874:                        break;
                    875:                }
                    876:                smux_fd = NOTOK;
                    877: 
                    878:           Note the use of the smux_trap routine to send a coldStart trap
                    879: 
                    880: 
                    881: 
                    882: 
                    883: 
                    884:           M.T. Rose                                            [Page 15]
                    885: 
                    886: 
                    887: 
                    888: 
                    889: 
                    890:           draft            Exporting MIBs for BSD UNIX          May 1990
                    891: 
                    892: 
                    893:           once the daemon has successful registered the MIB module it is
                    894:           exporting.  The trap codes are:
                    895: 
                    896:                int_SNMP_generic__trap_coldStart
                    897:                int_SNMP_generic__trap_warmStart
                    898:                int_SNMP_generic__trap_linkDown
                    899:                int_SNMP_generic__trap_linkUp
                    900:                int_SNMP_generic__trap_authenticationFailure
                    901:                int_SNMP_generic__trap_egpNeighborLoss
                    902:                int_SNMP_generic__trap_enterpriseSpecific
                    903: 
                    904:           If this routine fails, smux_errno will be set to one of
                    905:           invalidOperation, congestion, or youLoseBig.
                    906: 
                    907:           So, all that remains is to take a look at the routine get_smux
                    908:           which implements the SNMP get and powerful get-next operators.
                    909:           We will return to this routine once the structures and
                    910:           routines which implement the managed object abstraction are
                    911:           explained.
                    912: 
                    913: 
                    914: 
                    915: 
                    916: 
                    917: 
                    918: 
                    919: 
                    920: 
                    921: 
                    922: 
                    923: 
                    924: 
                    925: 
                    926: 
                    927: 
                    928: 
                    929: 
                    930: 
                    931: 
                    932: 
                    933: 
                    934: 
                    935: 
                    936: 
                    937: 
                    938: 
                    939: 
                    940: 
                    941: 
                    942: 
                    943:           M.T. Rose                                            [Page 16]
                    944: 
                    945: 
                    946: 
                    947: 
                    948: 
                    949:           draft            Exporting MIBs for BSD UNIX          May 1990
                    950: 
                    951: 
                    952:           6.  Managed Objects
                    953: 
                    954:           A managed object is an abstraction with a syntax and a
                    955:           semantics.  The syntax defines what instances of the object
                    956:           look like on the network.  The semantics define what the
                    957:           object actually is.
                    958: 
                    959: 
                    960:           6.1.  Syntax
                    961: 
                    962:           The syntax of MIB objects is modeled by the OS structure:
                    963: 
                    964:                typedef struct object_syntax {
                    965:                    char   *os_name;                    /* syntax name */
                    966: 
                    967:                    IFP     os_encode;                  /* data -> PE */
                    968:                    IFP     os_decode;                  /* PE -> data */
                    969:                    IFP     os_free;                    /* free data */
                    970: 
                    971:                    IFP     os_parse;                   /* str -> data */
                    972:                    IFP     os_print;                   /* data -> tty */
                    973: 
                    974:                         ...
                    975:                }               object_syntax, *OS;
                    976:                #define NULLOS  ((OS) 0)
                    977: 
                    978:           The syntaxes defined by the Internet-standard MIB are already
                    979:           implemented:
                    980: 
                    981:                syntax  structure
                    982:                INTEGER integer
                    983:                OctetString     struct qbuf (OCTET STRING)
                    984:                ObjectID        struct OIDentifier (OBJECT IDENTIFIER)
                    985:                NULL    char
                    986:                DisplayString   struct qbuf
                    987:                IpAddress       struct sockaddr_in
                    988:                NetworkAddress  struct sockaddr_in
                    989:                Counter integer
                    990:                Gauge   integer
                    991:                TimeTicks       integer
                    992:                ClnpAddress     struct sockaddr_iso
                    993: 
                    994:           where "syntax" is the name appearing in a compiled MIB module,
                    995:           and "structure" is the C language data type corresponding to
                    996:           the object's syntax.
                    997: 
                    998: 
                    999: 
                   1000: 
                   1001: 
                   1002:           M.T. Rose                                            [Page 17]
                   1003: 
                   1004: 
                   1005: 
                   1006: 
                   1007: 
                   1008:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1009: 
                   1010: 
                   1011:           To take a syntax name and get back the structure, use the
                   1012:           routine text2syn.
                   1013: 
                   1014: 
                   1015:           6.1.1.  Abstractions for Standard Syntaxes
                   1016: 
                   1017:           Here are the structures and routine used to implement the
                   1018:           low-level MIB abstractions.
                   1019: 
                   1020: 
                   1021:           6.1.1.1.  integer
                   1022: 
                   1023:           This is used for the INTEGER, Counter, Gauge, and TimeTicks
                   1024:           syntax.
                   1025: 
                   1026:           The definition is:
                   1027: 
                   1028:                typedef int integer;
                   1029: 
                   1030:           which is hardly surprising.
                   1031: 
                   1032: 
                   1033:           6.1.1.2.  struct qbuf
                   1034: 
                   1035:           This is used for the OctetString (OBJECT IDENTIFIER) and
                   1036:           DisplayString syntaxes.
                   1037: 
                   1038:           The definition is:
                   1039: 
                   1040:                struct qbuf {
                   1041:                    struct qbuf *qb_forw;   /* doubly-linked list */
                   1042:                    struct qbuf *qb_back;   /*   .. */
                   1043: 
                   1044:                    int     qb_len;         /* length of data */
                   1045:                    char   *qb_data;        /* current pointer into data */
                   1046:                    char    qb_base[1];     /* extensible... */
                   1047:                };
                   1048: 
                   1049:           The macro QBFREE is used to traverse qb_forw to free all qbufs
                   1050:           in the ring:
                   1051: 
                   1052:                QBFREE (qb)
                   1053:                struct qbuf *qb;
                   1054: 
                   1055:           To allocate a new string from the qbuf use:
                   1056: 
                   1057: 
                   1058: 
                   1059: 
                   1060: 
                   1061:           M.T. Rose                                            [Page 18]
                   1062: 
                   1063: 
                   1064: 
                   1065: 
                   1066: 
                   1067:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1068: 
                   1069: 
                   1070:                char *qb2str (q)
                   1071:                struct qbuf *q
                   1072: 
                   1073:           The string is NULL-terminated, but there may be other NULLs in
                   1074:           the string to foil things like strlen.
                   1075: 
                   1076:           To allocate a new qbuf of len octets from string s, use:
                   1077: 
                   1078:                struct qbuf str2qb (s, len, head)
                   1079:                char    *s;
                   1080:                int      len,
                   1081:                         head;
                   1082: 
                   1083:           (head should always be 1).
                   1084: 
                   1085:           To free an allocated qbuf, use qb_free which calls QBFREE and
                   1086:           then free on its argument.
                   1087: 
                   1088: 
                   1089:           6.1.1.3.  struct OIDentifier
                   1090: 
                   1091:           This is used for the ObjectID (OBJECT IDENTIFIER) syntax.  The
                   1092:           definition is:
                   1093: 
                   1094:                typedef struct OIDentifier {
                   1095:                    int     oid_nelem;  /* number of sub-identifiers */
                   1096: 
                   1097:                    unsigned int *oid_elements;
                   1098:                        /* the (ordered) list of sub-identifiers */
                   1099:                }                       OIDentifier, *OID;
                   1100:                #define NULLOID ((OID) 0)
                   1101: 
                   1102:           To compare two OIDs, use
                   1103: 
                   1104:                int     oid_cmp (p, q)
                   1105:                OID     p,
                   1106:                        q;
                   1107: 
                   1108:           which returns -1 if p<q, 1 if p>q, 0 otherwise.
                   1109: 
                   1110:           To allocate a new OID and copy it from another, use oid_cpy.
                   1111: 
                   1112:           To free an allocated OID, use oid_free.
                   1113: 
                   1114: 
                   1115: 
                   1116: 
                   1117: 
                   1118: 
                   1119: 
                   1120:           M.T. Rose                                            [Page 19]
                   1121: 
                   1122: 
                   1123: 
                   1124: 
                   1125: 
                   1126:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1127: 
                   1128: 
                   1129:           To take an OID and produce a string in numeric form use
                   1130: 
                   1131:                char   *sprintoid (oid)
                   1132:                OID     oid;
                   1133: 
                   1134:           The result is returned in a static area.  The inverse routine
                   1135:           is:
                   1136: 
                   1137:                OID     str2oid (s)
                   1138:                char    *s;
                   1139: 
                   1140:           which returns an OID from a static area
                   1141: 
                   1142: 
                   1143:           6.1.1.4.  struct sockaddr_in
                   1144: 
                   1145:           This is used for the IpAddress and NetworkAddress syntaxes.
                   1146:           Presumably you are overly familiar with this structure.
                   1147: 
                   1148: 
                   1149:           6.1.1.5.  struct sockaddr_iso
                   1150: 
                   1151:           This is used for the ClnpAddress syntax.  If your are not
                   1152:           running a BSD/OSI system, don't worry about this.
                   1153: 
                   1154: 
                   1155:           6.1.2.  Defining a new Syntax
                   1156: 
                   1157:           The routine add_syntax is used to define a new syntax.  (if
                   1158:           this routine returns NOTOK, then the internal syntax table has
                   1159:           overflowed; adjust the constant MAXSYN in the file syntax.c).
                   1160:           The first argument is the name of the syntax.  The other five
                   1161:           are pointers to integer-valued routines that are called to
                   1162:           operate on an opaque pointer:
                   1163: 
                   1164:                /* returns OK if x is encoded into pe (allocates pe),
                   1165:                   NOTOK otherwise */
                   1166: 
                   1167:                f_encode (x, pe)
                   1168:                pointer *x;
                   1169:                PE      *pe;
                   1170: 
                   1171: 
                   1172:                /* returns OK if pe is decoded into x (allocates x),
                   1173:                   NOTOK otherwise */
                   1174: 
                   1175: 
                   1176: 
                   1177: 
                   1178: 
                   1179:           M.T. Rose                                            [Page 20]
                   1180: 
                   1181: 
                   1182: 
                   1183: 
                   1184: 
                   1185:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1186: 
                   1187: 
                   1188:                f_decode (x, pe)
                   1189:                pointer **x;
                   1190:                PE        pe;
                   1191: 
                   1192: 
                   1193:                /* free's an allocated x (from f_decode or f_parse) */
                   1194: 
                   1195:                f_free (x)
                   1196:                pointer *x;
                   1197: 
                   1198: 
                   1199:                /* returns OK if s is decoded into x (allocates x),
                   1200:                   NOTOK otherwise */
                   1201: 
                   1202:                f_parse (x, s)
                   1203:                pointer **x;
                   1204:                char     *s;
                   1205: 
                   1206: 
                   1207:                /* prints x on the user's tty */
                   1208: 
                   1209:                f_print (x, os)
                   1210:                pointer *x;
                   1211:                OS       os;
                   1212: 
                   1213:           Presentation elements (PEs) are discussed later on.
                   1214: 
                   1215: 
                   1216:           6.2.  Objects
                   1217: 
                   1218:           MIB objects are modeled by the OT structure:
                   1219: 
                   1220:                typedef struct object_type {
                   1221:                    char   *ot_text;                /* OBJECT DESCRIPTOR */
                   1222:                    char   *ot_id;                  /* OBJECT IDENTIFIER */
                   1223:                    OID     ot_name;                /*   .. */
                   1224: 
                   1225:                    OS      ot_syntax;              /* SYNTAX */
                   1226: 
                   1227:                    int     ot_access;              /* ACCESS */
                   1228:                #define OT_NONE         0x00
                   1229:                #define OT_RDONLY       0x01
                   1230:                #define OT_RDWRITE      0x02
                   1231: 
                   1232:                    int     ot_status;              /* STATUS */
                   1233: 
                   1234: 
                   1235: 
                   1236: 
                   1237: 
                   1238:           M.T. Rose                                            [Page 21]
                   1239: 
                   1240: 
                   1241: 
                   1242: 
                   1243: 
                   1244:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1245: 
                   1246: 
                   1247:                #define OT_OBSOLETE     0x00
                   1248:                #define OT_MANDATORY    0x01
                   1249:                #define OT_OPTIONAL     0x02
                   1250:                #define OT_DEPRECATED   0x03
                   1251: 
                   1252:                     ...
                   1253:                }               object_type, *OT;
                   1254:                #define NULLOT  ((OT) 0)
                   1255: 
                   1256:           There are lots of routines to manipulate MIB objects.
                   1257: 
                   1258:           The routine name2obj takes an object identifier and returns
                   1259:           the object type, either exact or prefix, e.g.,
                   1260: 
                   1261:                name2obj ( OID { ipRouteDest.0.0.0.0 } )
                   1262: 
                   1263:           returns the object type for "ipRouteDest"
                   1264: 
                   1265:           The routine text2obj takes a string and returns the exact
                   1266:           object type, e.g.,
                   1267: 
                   1268:                text2obj ("ipRouteDest")
                   1269: 
                   1270:           will succeed, but
                   1271: 
                   1272:                text2obj ("ipRouteDest.0.0.0.0")
                   1273: 
                   1274:           will fail.
                   1275: 
                   1276:           The routine text2oid takes a string and returns the object
                   1277:           identifier associated with the corresponding object.  The
                   1278:           string can be numeric (e.g., "1.3.6.1"), symbolic (e.g.,
                   1279:           "internet"), or symbolic.numeric (e.g., "iso.3.6.1").
                   1280: 
                   1281:           The routine oid2ode takes an OID and returns a string suitable
                   1282:           for pretty-printing, in the form symbolic or symbolic.numeric.
                   1283: 
                   1284: 
                   1285:           6.3.  Instances
                   1286: 
                   1287:           MIB instances are modeled by the OI structure:
                   1288: 
                   1289:                typedef struct object_instance {
                   1290:                    OID     oi_name;                /* instance OID */
                   1291: 
                   1292: 
                   1293: 
                   1294: 
                   1295: 
                   1296: 
                   1297:           M.T. Rose                                            [Page 22]
                   1298: 
                   1299: 
                   1300: 
                   1301: 
                   1302: 
                   1303:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1304: 
                   1305: 
                   1306:                    OT      oi_type;                /* prototype */
                   1307:                }               object_instance, *OI;
                   1308:                #define NULLOI  ((OI) 0)
                   1309: 
                   1310:           There are lots of routines to manipulate MIB instances.
                   1311: 
                   1312:           The routine name2inst takes a variable name and returns the
                   1313:           corresponding instance, e.g.,
                   1314: 
                   1315:                name2inst ( OID { ipRouteDest.0.0.0.0 } )
                   1316: 
                   1317:           will return an OI with oi_name set to its argument and oi_type
                   1318:           set to the object type for "ipRouteDest".
                   1319: 
                   1320:           The routine next2inst finds the closest object type before the
                   1321:           variable name and returns an OI corresponding to that object
                   1322:           type.
                   1323: 
                   1324:           The routine text2inst first calls text2oid to get the OID
                   1325:           corresponding to the argument, then calls name2obj to get the
                   1326:           type associated with that OID.
                   1327: 
                   1328: 
                   1329: 
                   1330: 
                   1331: 
                   1332: 
                   1333: 
                   1334: 
                   1335: 
                   1336: 
                   1337: 
                   1338: 
                   1339: 
                   1340: 
                   1341: 
                   1342: 
                   1343: 
                   1344: 
                   1345: 
                   1346: 
                   1347: 
                   1348: 
                   1349: 
                   1350: 
                   1351: 
                   1352: 
                   1353: 
                   1354: 
                   1355: 
                   1356:           M.T. Rose                                            [Page 23]
                   1357: 
                   1358: 
                   1359: 
                   1360: 
                   1361: 
                   1362:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1363: 
                   1364: 
                   1365:           7.  Linkage
                   1366: 
                   1367:           It is now time to tie up all the loose ends.  When your
                   1368:           program starts, it needs to establish some linkage between the
                   1369:           objects defined in the compiled MIB module and the data
                   1370:           structures in your program.  Further, when the SNMP agent asks
                   1371:           to manipulate the object instances in the MIB module your
                   1372:           program exported (e.g., using the powerful SNMP get-next
                   1373:           operator), you need to have a small protocol engine to field
                   1374:           these requests.
                   1375: 
                   1376:           The way the linkage is established is to associate a C routine
                   1377:           with each of the leaf objects defined in the compiled MIB
                   1378:           module.  When the protocol engine fields a request from the
                   1379:           SNMP agent, it will invoke that routine to "do the right
                   1380:           thing".  Typically, for each table in the compiled MIB module,
                   1381:           you define a C routine to handle requests for the leaf objects
                   1382:           of that table.  In addition, there is usually one more routine
                   1383:           defined to handle those leaf objects not found under any one
                   1384:           table.  For each C routine you define, you define a group of
                   1385:           constant integer symbols which identify a leaf object that is
                   1386:           handled by that routine (e.g., for each routine, you start
                   1387:           numbering the symbols starting at 0 and going up).  By
                   1388:           convention, these symbols have the same name as the leaf
                   1389:           objects.
                   1390: 
                   1391: 
                   1392:           7.1.  Initialization
                   1393: 
                   1394:           Earlier it was noted that your program will probably call a
                   1395:           routine called init_mib which initializes it's internal MIB
                   1396:           structures.  The routine should look something like this:
                   1397: 
                   1398:                register OT     ot;
                   1399: 
                   1400:                if (ot = text2obj ("mbufS"))
                   1401:                    ot -> ot_getfnx = o_mbuf,
                   1402:                    ot -> ot_info = (caddr_t) mbufS;
                   1403: 
                   1404:                 ...
                   1405: 
                   1406:                if (ot = text2obj ("mbufType"))
                   1407:                    ot -> ot_getfnx = o_mbufType,
                   1408:                    ot -> ot_info = (caddr_t) mbufType;
                   1409: 
                   1410: 
                   1411: 
                   1412: 
                   1413: 
                   1414: 
                   1415:           M.T. Rose                                            [Page 24]
                   1416: 
                   1417: 
                   1418: 
                   1419: 
                   1420: 
                   1421:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1422: 
                   1423: 
                   1424:           where we can imagine that o_mbuf and o_mbufType are routines
                   1425:           that are defined in your program, and mbufS and mbufType are
                   1426:           constant symbols defined with those routines.
                   1427: 
                   1428: 
                   1429:           7.2.  Generic Event Handling
                   1430: 
                   1431:           Earlier it was noted that your program will probably call a
                   1432:           routine called get_smux which implements the SNMP get and
                   1433:           powerful get-next operators.  The routine should look
                   1434:           something like this:
                   1435: 
                   1436:                static  get_smux (pdu, offset)
                   1437:                register struct type_SNMP_GetRequest__PDU *pdu;
                   1438:                int     offset;
                   1439:                {
                   1440:                    int     idx,
                   1441:                            status;
                   1442:                    object_instance ois;
                   1443:                    register struct type_SNMP_VarBindList *vp;
                   1444: 
                   1445:                    quantum = pdu -> request__id;
                   1446:                    idx = 0;
                   1447:                    for (vp = pdu -> variable__bindings; vp; vp = vp -> next) {
                   1448:                        register OI     oi;
                   1449:                        register OT     ot;
                   1450:                        register struct type_SNMP_VarBind *v = vp -> VarBind;
                   1451: 
                   1452:                        idx++;
                   1453: 
                   1454:                        if (offset == type_SNMP_SMUX__PDUs_get__next__request) {
                   1455:                            if ((oi = name2inst (v -> name)) == NULLOI
                   1456:                                    && (oi = next2inst (v -> name)) == NULLOI)
                   1457:                                goto no_name;
                   1458: 
                   1459:                            if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP)
                   1460:                                goto get_next;
                   1461:                        }
                   1462:                        else
                   1463:                            if ((oi = name2inst (v -> name)) == NULLOI
                   1464:                                    || (ot = oi -> oi_type) -> ot_getfnx
                   1465:                                            == NULLIFP) {
                   1466:                no_name: ;
                   1467:                                pdu -> error__status =
                   1468:                                        int_SNMP_error__status_noSuchName;
                   1469: 
                   1470: 
                   1471: 
                   1472: 
                   1473: 
                   1474:           M.T. Rose                                            [Page 25]
                   1475: 
                   1476: 
                   1477: 
                   1478: 
                   1479: 
                   1480:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1481: 
                   1482: 
                   1483:                                goto out;
                   1484:                            }
                   1485: 
                   1486:                try_again: ;
                   1487:                        switch (ot -> ot_access) {
                   1488:                            case OT_NONE:
                   1489:                                if (offset ==
                   1490:                                        type_SNMP_SMUX__PDUs_get__next__request)
                   1491:                                    goto get_next;
                   1492:                                goto no_name;
                   1493: 
                   1494:                            case OT_RDONLY:
                   1495:                                if (offset ==
                   1496:                                        type_SNMP_SMUX__PDUs_set__request) {
                   1497:                                    pdu -> error__status =
                   1498:                                                int_SNMP_error__status_readOnly;
                   1499:                                    goto out;
                   1500:                                }
                   1501:                                break;
                   1502: 
                   1503:                            case OT_RDWRITE:
                   1504:                                break;
                   1505:                        }
                   1506: 
                   1507:                        switch (status = (*ot -> ot_getfnx) (oi, v, offset)) {
                   1508:                            case NOTOK:     /* get-next wants a bump */
                   1509:                get_next: ;
                   1510:                                oi = &ois;
                   1511:                                for (;;) {
                   1512:                                    if ((ot = ot -> ot_next) == NULLOT) {
                   1513:                                        pdu -> error__status =
                   1514:                                              int_SNMP_error__status_noSuchName;
                   1515:                                        goto out;
                   1516:                                    }
                   1517:                                    oi -> oi_name =
                   1518:                                                (oi -> oi_type = ot) -> ot_name;
                   1519:                                    if (ot -> ot_getfnx)
                   1520:                                        goto try_again;
                   1521:                                }
                   1522: 
                   1523:                            case int_SNMP_error__status_noError:
                   1524:                                break;
                   1525: 
                   1526:                            default:
                   1527:                                pdu -> error__status = status;
                   1528: 
                   1529: 
                   1530: 
                   1531: 
                   1532: 
                   1533:           M.T. Rose                                            [Page 26]
                   1534: 
                   1535: 
                   1536: 
                   1537: 
                   1538: 
                   1539:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1540: 
                   1541: 
                   1542:                                goto out;
                   1543:                        }
                   1544:                    }
                   1545:                    idx = 0;
                   1546: 
                   1547:                out: ;
                   1548:                    pdu -> error__index = idx;
                   1549: 
                   1550:                    if (smux_response (pdu) == NOTOK) {
                   1551:                        error ("smux_response: %s [%s]",
                   1552:                               smux_error (smux_errno), smux_info);
                   1553:                        smux_fd = NOTOK;
                   1554:                    }
                   1555:                }
                   1556: 
                   1557:           The actual code is fairly straight-forward: First, the
                   1558:           variable quantum is set to the request ID for this
                   1559:           transaction.  The SMUX protocol requires that this number
                   1560:           change for each SNMP operation that the SNMP agent fields, so
                   1561:           your program can use it as a cookie to see when it should re-
                   1562:           read kernel variables.  (A single SNMP operation received by
                   1563:           the SNMP agent might result in multiple SMUX protocol
                   1564:           transactions with your program.)
                   1565: 
                   1566:           Next, the code loops through the list of variables requested.
                   1567:           The object instance is determined and loaded into oin and the
                   1568:           corresponding object type is loaded into ot, and the access is
                   1569:           checked.
                   1570: 
                   1571:           Finally, the user-defined routine is invoked.  This routine
                   1572:           returns one of these values:
                   1573: 
                   1574:                NOTOK
                   1575:                int_SNMP_error__status_noError
                   1576:                int_SNMP_error__status_tooBig
                   1577:                int_SNMP_error__status_noSuchName
                   1578:                int_SNMP_error__status_badValue
                   1579:                int_SNMP_error__status_readOnly
                   1580:                int_SNMP_error__status_genErr
                   1581: 
                   1582:           the first value is returned only if the powerful get-next
                   1583:           operator is being invoked and the routine didn't have any more
                   1584:           object instances for the object type in question.  The
                   1585:           remainder are all self-explanatory.
                   1586: 
                   1587: 
                   1588: 
                   1589: 
                   1590: 
                   1591: 
                   1592:           M.T. Rose                                            [Page 27]
                   1593: 
                   1594: 
                   1595: 
                   1596: 
                   1597: 
                   1598:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1599: 
                   1600: 
                   1601:           Once an answer is returned, the loop either continues or is
                   1602:           broken and a response is written back using the smux_response
                   1603:           routine.  On failure, smux_error will be set to one of
                   1604:           parameterMissing, invalidOperation, or youLoseBig.
                   1605: 
                   1606: 
                   1607:           7.3.  Specific Event Handling: Outside a table
                   1608: 
                   1609:           Now let's look at one of these user-defined routines, which
                   1610:           handles leaf objects that are not part of a table:
                   1611: 
                   1612:                static  int     lastq = -1;
                   1613:                static  struct mbstat mbstat;
                   1614: 
                   1615: 
                   1616:                #define mbufS           0
                   1617:                #define mbufClusters    1
                   1618:                 ...
                   1619:                #define mbufFrees       6
                   1620: 
                   1621: 
                   1622:                static int  o_mbuf (oi, v, offset)
                   1623:                OI      oi;
                   1624:                register struct type_SNMP_VarBind *v;
                   1625:                int     offset;
                   1626:                {
                   1627:                    int     ifvar;
                   1628:                    register struct mbstat *m = &mbstat;
                   1629:                    register OID    oid = oi -> oi_name;
                   1630:                    register OT     ot = oi -> oi_type;
                   1631: 
                   1632:                    ifvar = (int) ot -> ot_info;
                   1633:                    switch (offset) {
                   1634:                        case type_SNMP_SMUX__PDUs_get__request:
                   1635:                            if (oid -> oid_nelem !=
                   1636:                                        ot -> ot_name -> oid_nelem + 1
                   1637:                                    || oid -> oid_elements[oid -> oid_nelem - 1]
                   1638:                                            != 0)
                   1639:                                return int_SNMP_error__status_noSuchName;
                   1640:                            break;
                   1641: 
                   1642:                        case type_SNMP_SMUX__PDUs_get__next__request:
                   1643:                            if (oid -> oid_nelem
                   1644:                                    == ot -> ot_name -> oid_nelem) {
                   1645:                                OID     new;
                   1646: 
                   1647: 
                   1648: 
                   1649: 
                   1650: 
                   1651:           M.T. Rose                                            [Page 28]
                   1652: 
                   1653: 
                   1654: 
                   1655: 
                   1656: 
                   1657:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1658: 
                   1659: 
                   1660:                                if ((new = oid_extend (oid, 1)) == NULLOID)
                   1661:                                    return int_SNMP_error__status_genErr;
                   1662:                                new -> oid_elements[new -> oid_nelem - 1] = 0;
                   1663: 
                   1664:                                if (v -> name)
                   1665:                                    free_SNMP_ObjectName (v -> name);
                   1666:                                v -> name = new;
                   1667:                            }
                   1668:                            else
                   1669:                                return NOTOK;
                   1670:                            break;
                   1671: 
                   1672:                        default:
                   1673:                            return int_SNMP_error__status_genErr;
                   1674:                    }
                   1675: 
                   1676:                    if (quantum != lastq) {
                   1677:                        lastq = quantum;
                   1678: 
                   1679:                        if (getkmem (nl + N_MBSTAT, (caddr_t) m, sizeof *m)
                   1680:                                == NOTOK)
                   1681:                            return int_SNMP_error__status_genErr;
                   1682:                    }
                   1683: 
                   1684:                    switch (ifvar) {
                   1685:                        case mbufS:
                   1686:                            return o_integer (oi, v, m -> m_mbufs);
                   1687: 
                   1688:                        case mbufClusters:
                   1689:                            return o_integer (oi, v, m -> m_clusters);
                   1690: 
                   1691:                 ...
                   1692: 
                   1693:                        case mbufFrees:
                   1694:                            return o_integer (oi, v, m -> m_mbfree);
                   1695: 
                   1696:                        default:
                   1697:                            return int_SNMP_error__status_noSuchName;
                   1698:                    }
                   1699:                }
                   1700: 
                   1701:           The actual code is fairly straight-forward: First, the
                   1702:           constant offsets are defined.  Then, the o_mbuf routine is
                   1703:           defined.
                   1704: 
                   1705: 
                   1706: 
                   1707: 
                   1708: 
                   1709: 
                   1710:           M.T. Rose                                            [Page 29]
                   1711: 
                   1712: 
                   1713: 
                   1714: 
                   1715: 
                   1716:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1717: 
                   1718: 
                   1719:           The first action is to determine which leaf object is being
                   1720:           referenced.  This corresponding symbolic constant is placed in
                   1721:           the variable ifvar.  Then a switch is made based on the
                   1722:           operation.
                   1723: 
                   1724:           (1)  For the get operation, all instances are identified by
                   1725:                the object type followed by ".0" (e.g., "mbufS.0").  So,
                   1726:                the code checks to see if the OID associated with the
                   1727:                object instance is exactly one longer than the OID
                   1728:                associated with the object type, and that the extra sub-
                   1729:                identifier has the value 0.
                   1730: 
                   1731:           (2)  For the powerful get-next operation, there are really two
                   1732:                cases, depending on whether some instance identifier is
                   1733:                present.  If some instance identifier is present, then
                   1734:                for a non-tabular leaf object, the next variable belongs
                   1735:                to some other object type, so the routine simply returns
                   1736:                the value NOTOK, and the get_smux routine will find the
                   1737:                next object accordingly.  Otherwise, if no instance is
                   1738:                identified, a new OID is constructed and initialized.
                   1739:                The old OID is free'd and the new one inserted in its
                   1740:                place.
                   1741: 
                   1742:           Now that the correct instance has been identified, a check is
                   1743:           made to see if kmem should be consulted.  (Obviously other
                   1744:           programs might consult other data stores.) Finally, the
                   1745:           instance value is encoded and the routine returns.
                   1746: 
                   1747: 
                   1748:           7.3.1.  Instance handling
                   1749: 
                   1750:           Several routines are provided to encode instance values:
                   1751: 
                   1752:           The o_number routine encodes an integer value, such as an
                   1753:           INTEGER, Counter, Guage, or TimeTick.  The macro o_integer is
                   1754:           simply a synonym for o_number.
                   1755: 
                   1756:           The o_string routine encodes a string value, such as an
                   1757:           OctetString or DisplayString, e.g.,
                   1758: 
                   1759:                o_string (oi, v, "lo0", strlen ("lo0"));
                   1760: 
                   1761:           or
                   1762: 
                   1763:                o_string (oi, v, ether_addr, sizeof ether_addr);
                   1764: 
                   1765: 
                   1766: 
                   1767: 
                   1768: 
                   1769:           M.T. Rose                                            [Page 30]
                   1770: 
                   1771: 
                   1772: 
                   1773: 
                   1774: 
                   1775:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1776: 
                   1777: 
                   1778:           The o_specific routine takes a structure corresponding to a
                   1779:           syntax, such as an OID for ObjectID, and does the encoding,
                   1780:           e.g.,
                   1781: 
                   1782:                OID nullSpecific = ...;
                   1783: 
                   1784:                o_specific (oi, v, nullSpecific);
                   1785: 
                   1786: 
                   1787: 
                   1788:           7.3.2.  A special case
                   1789: 
                   1790:           A special user-defined routine is provided for those cases for
                   1791:           leaf-objects containing information that is initialized on
                   1792:           start-up, o_generic.  For example:
                   1793: 
                   1794:                char    buffer[BUFSIZ];
                   1795: 
                   1796:                if (ot = text2obj ("sysName"))
                   1797:                    ot -> ot_getfnx = o_generic,
                   1798:                    ot -> ot_info = (caddr_t) sysName;
                   1799: 
                   1800:                (void) gethostname (buffer, sizeof buffer);
                   1801:                (void) (*ot -> ot_syntax -> os_parse)
                   1802:                                ((struct qbuf **) &ot -> ot_info, buffer);
                   1803: 
                   1804:           The idea is that the ot_info field contains a pointer to a
                   1805:           data structure corresponding to the syntax of the object.
                   1806:           Since all of the structures are rather strange (except for
                   1807:           integers), o_generic probably won't receive a lot of use.
                   1808: 
                   1809: 
                   1810:           7.4.  Specific Event Handling: Inside a table
                   1811: 
                   1812:           Now let's look at one of these user-defined routines, which
                   1813:           handles leaf objects that are part of a table:
                   1814: 
                   1815:                #define mbufType        0
                   1816:                #define mbufAllocates   1
                   1817: 
                   1818: 
                   1819:                static int  o_mbufType (oi, v, offset)
                   1820:                OI      oi;
                   1821:                register struct type_SNMP_VarBind *v;
                   1822:                int     offset;
                   1823: 
                   1824: 
                   1825: 
                   1826: 
                   1827: 
                   1828:           M.T. Rose                                            [Page 31]
                   1829: 
                   1830: 
                   1831: 
                   1832: 
                   1833: 
                   1834:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1835: 
                   1836: 
                   1837:                {
                   1838:                    int     ifnum,
                   1839:                            ifvar;
                   1840:                    register struct mbstat *m = &mbstat;
                   1841:                    register OID    oid = oi -> oi_name;
                   1842:                    register OT     ot = oi -> oi_type;
                   1843: 
                   1844:                    ifvar = (int) ot -> ot_info;
                   1845:                    switch (offset) {
                   1846:                        case type_SNMP_SMUX__PDUs_get__request:
                   1847:                            if (oid -> oid_nelem
                   1848:                                    != ot -> ot_name -> oid_nelem + 1)
                   1849:                                return int_SNMP_error__status_noSuchName;
                   1850:                            ifnum =
                   1851:                                  oid -> oid_elements[oid -> oid_nelem - 1];
                   1852:                            if (ifvar >= sizeof m -> m_mtypes /
                   1853:                                            sizeof m -> m_mtypes[0])
                   1854:                                return int_SNMP_error__status_noSuchName;
                   1855:                            break;
                   1856: 
                   1857:                        case type_SNMP_SMUX__PDUs_get__next__request:
                   1858:                            if (oid -> oid_nelem
                   1859:                                    == ot -> ot_name -> oid_nelem) {
                   1860:                                OID     new;
                   1861: 
                   1862:                                ifnum = 0;
                   1863: 
                   1864:                                if ((new = oid_extend (oid, 1)) == NULLOID)
                   1865:                                    return int_SNMP_error__status_genErr;
                   1866:                                new -> oid_elements[new -> oid_nelem - 1] =
                   1867:                                                ifnum;
                   1868: 
                   1869:                                if (v -> name)
                   1870:                                    free_SNMP_ObjectName (v -> name);
                   1871:                                v -> name = new;
                   1872:                            }
                   1873:                            else {
                   1874:                                int     i = ot -> ot_name -> oid_nelem;
                   1875: 
                   1876:                                ifnum = oid -> oid_elements[i] + 1;
                   1877:                                if (ifnum >= sizeof m -> m_mtypes /
                   1878:                                                sizeof m -> m_mtypes[0])
                   1879:                                    return NOTOK;
                   1880: 
                   1881:                                oid -> oid_elements[i] = ifnum;
                   1882: 
                   1883: 
                   1884: 
                   1885: 
                   1886: 
                   1887:           M.T. Rose                                            [Page 32]
                   1888: 
                   1889: 
                   1890: 
                   1891: 
                   1892: 
                   1893:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1894: 
                   1895: 
                   1896:                                oid -> oid_nelem = i + 1;
                   1897:                            }
                   1898:                            break;
                   1899: 
                   1900:                        default:
                   1901:                            return int_SNMP_error__status_genErr;
                   1902:                    }
                   1903: 
                   1904:                    if (quantum != lastq) {
                   1905:                        lastq = quantum;
                   1906: 
                   1907:                        if (getkmem (nl + N_MBSTAT, (caddr_t) m, sizeof *m)
                   1908:                                == NOTOK)
                   1909:                            return int_SNMP_error__status_genErr;
                   1910:                    }
                   1911: 
                   1912:                    switch (ifvar) {
                   1913:                        case mbufType:
                   1914:                            return o_integer (oi, v, ifnum);
                   1915: 
                   1916:                        case mbufAllocates:
                   1917:                            return o_integer (oi, v,
                   1918:                                              m -> m_mtypes[ifnum]);
                   1919: 
                   1920:                        default:
                   1921:                            return int_SNMP_error__status_noSuchName;
                   1922:                    }
                   1923:                }
                   1924: 
                   1925:           The actual code is fairly straight-forward: First, the
                   1926:           constant offsets are defined.  Then, the o_mbufType routine is
                   1927:           defined.
                   1928: 
                   1929:           The first action is to determine which leaf object is being
                   1930:           referenced.  This corresponding symbolic constant is placed in
                   1931:           the variable ifvar.  Then a switch is made based on the
                   1932:           operation.  Because these are tabular objects, the instance
                   1933:           refers to a row in the table (and the leaf object refers to a
                   1934:           column in the table, of course).
                   1935: 
                   1936:           (1)  For the get operation, all instances are identified by
                   1937:                the object type followed by ".rowno" (e.g.,
                   1938:                "mbufAllocates.10") refers to the value in the
                   1939:                mbufAllocates column of the thenth row).  So, the code
                   1940:                checks to see if the OID associated with the object
                   1941: 
                   1942: 
                   1943: 
                   1944: 
                   1945: 
                   1946:           M.T. Rose                                            [Page 33]
                   1947: 
                   1948: 
                   1949: 
                   1950: 
                   1951: 
                   1952:           draft            Exporting MIBs for BSD UNIX          May 1990
                   1953: 
                   1954: 
                   1955:                instance is exactly one longer than the OID associated
                   1956:                with the object type, and that the extra sub-identifier
                   1957:                is within the range 0..rowno-1.
                   1958: 
                   1959:           (2)  For the powerful get-next operation, there are really two
                   1960:                cases, depending on whether some instance identifier is
                   1961:                present.  If no instance is identified, a new OID is
                   1962:                constructed and initialized for the first row (row 0) of
                   1963:                the table. The old OID is free'd and the new one inserted
                   1964:                in its place.  Otherwise, if some instance identifier is
                   1965:                present, then the corresponding row must be identified,
                   1966:                the row number incremented, and a check made to see if
                   1967:                this is still in range (if not, NOTOK is returned to
                   1968:                signal that the next object type should be used).
                   1969:                Otherwise, the OID is updated in place.
                   1970: 
                   1971:           Now that the correct instance has been identified, a check is
                   1972:           made to see if kmem should be consulted.  (Obviously other
                   1973:           programs might consult other data stores.) Finally, the
                   1974:           instance value is encoded and the routine returns.
                   1975: 
                   1976: 
                   1977:           7.4.1.  The general case
                   1978: 
                   1979:           Obviously, this is a simple example of table handling.  In
                   1980:           general, the table will be implemented via linked lists,
                   1981:           sorted according to object instance.  In this case, there is
                   1982:           usually a special routine that is called to get a particular
                   1983:           instance or the next instance.  Take a look at the routines
                   1984:           get_tbent and o_smuxTree in the file snmpd.c.  These implement
                   1985:           the smuxTree table.
                   1986: 
                   1987: 
                   1988: 
                   1989: 
                   1990: 
                   1991: 
                   1992: 
                   1993: 
                   1994: 
                   1995: 
                   1996: 
                   1997: 
                   1998: 
                   1999: 
                   2000: 
                   2001: 
                   2002: 
                   2003: 
                   2004: 
                   2005:           M.T. Rose                                            [Page 34]
                   2006: 
                   2007: 
                   2008: 
                   2009: 
                   2010: 
                   2011:           draft            Exporting MIBs for BSD UNIX          May 1990
                   2012: 
                   2013: 
                   2014:           Table of Contents
                   2015: 
                   2016: 
                   2017:           1 Status of this Memo ...................................    1
                   2018:           2 The Environment .......................................    2
                   2019:           2.1 The ISODE ...........................................    2
                   2020:           3 MIB Modules ...........................................    3
                   2021:           3.1 Compiling MIB modules ...............................    4
                   2022:           3.1.1 The Syntax of compiled MIB modules ................    5
                   2023:           4 SMUX Peers ............................................    6
                   2024:           5 Daemon Skeleton .......................................    7
                   2025:           5.1 Declarations ........................................    7
                   2026:           5.2 Initialization ......................................    8
                   2027:           5.3 Reading the compiled MIB module .....................    8
                   2028:           5.4 Talking to the SNMP agent ...........................    9
                   2029:           5.4.1 Initialization ....................................   10
                   2030:           5.4.2 Opening ...........................................   10
                   2031:           5.4.3 Closing ...........................................   11
                   2032:           5.4.4 Registering Subtrees ..............................   11
                   2033:           5.4.5 Main Loop .........................................   12
                   2034:           5.4.6 Events ............................................   14
                   2035:           6 Managed Objects .......................................   17
                   2036:           6.1 Syntax ..............................................   17
                   2037:           6.1.1 Abstractions for Standard Syntaxes ................   18
                   2038:           6.1.1.1 integer .........................................   18
                   2039:           6.1.1.2 struct qbuf .....................................   18
                   2040:           6.1.1.3 struct OIDentifier ..............................   19
                   2041:           6.1.1.4 struct sockaddr_in ..............................   20
                   2042:           6.1.1.5 struct sockaddr_iso .............................   20
                   2043:           6.1.2 Defining a new Syntax .............................   20
                   2044:           6.2 Objects .............................................   21
                   2045:           6.3 Instances ...........................................   22
                   2046:           7 Linkage ...............................................   24
                   2047:           7.1 Initialization ......................................   24
                   2048:           7.2 Generic Event Handling ..............................   25
                   2049:           7.3 Specific Event Handling: Outside a table ............   28
                   2050:           7.3.1 Instance handling .................................   30
                   2051:           7.3.2 A special case ....................................   31
                   2052:           7.4 Specific Event Handling: Inside a table .............   31
                   2053:           7.4.1 The general case ..................................   34
                   2054: 
                   2055: 
                   2056: 
                   2057: 
                   2058: 
                   2059: 
                   2060: 
                   2061: 
                   2062: 
                   2063: 
                   2064:           M.T. Rose                                            [Page 35]
                   2065: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.