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

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

unix.superglobalmegacorp.com

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