net-snmp 5.7
scalar_group.c
00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #include <net-snmp/net-snmp-includes.h>
00004 #include <net-snmp/agent/net-snmp-agent-includes.h>
00005 
00006 #include <net-snmp/agent/scalar_group.h>
00007 
00008 #include <stdlib.h>
00009 #if HAVE_STRING_H
00010 #include <string.h>
00011 #else
00012 #include <strings.h>
00013 #endif
00014 
00015 #include <net-snmp/agent/instance.h>
00016 #include <net-snmp/agent/serialize.h>
00017 
00018 static netsnmp_scalar_group*
00019 clone_scalar_group(netsnmp_scalar_group* src)
00020 {
00021   netsnmp_scalar_group *t = SNMP_MALLOC_TYPEDEF(netsnmp_scalar_group);
00022   if(t != NULL) {
00023     t->lbound = src->lbound;
00024     t->ubound = src->ubound;
00025   }
00026   return t;
00027 }
00028 
00034 netsnmp_mib_handler *
00035 netsnmp_get_scalar_group_handler(oid first, oid last)
00036 {
00037     netsnmp_mib_handler  *ret    = NULL;
00038     netsnmp_scalar_group *sgroup = NULL;
00039 
00040     ret = netsnmp_create_handler("scalar_group",
00041                                   netsnmp_scalar_group_helper_handler);
00042     if (ret) {
00043         sgroup = SNMP_MALLOC_TYPEDEF(netsnmp_scalar_group);
00044         if (NULL == sgroup) {
00045             netsnmp_handler_free(ret);
00046             ret = NULL;
00047         }
00048         else {
00049             sgroup->lbound = first;
00050             sgroup->ubound = last;
00051             ret->myvoid = (void *)sgroup;
00052             ret->data_free = free;
00053             ret->data_clone = (void *(*)(void *))clone_scalar_group;
00054         }
00055     }
00056     return ret;
00057 }
00058 
00059 int
00060 netsnmp_register_scalar_group(netsnmp_handler_registration *reginfo,
00061                               oid first, oid last)
00062 {
00063     netsnmp_inject_handler(reginfo, netsnmp_get_instance_handler());
00064     netsnmp_inject_handler(reginfo, netsnmp_get_scalar_group_handler(first, last));
00065     return netsnmp_register_serialize(reginfo);
00066 }
00067 
00068 
00069 int
00070 netsnmp_scalar_group_helper_handler(netsnmp_mib_handler *handler,
00071                                 netsnmp_handler_registration *reginfo,
00072                                 netsnmp_agent_request_info *reqinfo,
00073                                 netsnmp_request_info *requests)
00074 {
00075     netsnmp_variable_list *var = requests->requestvb;
00076 
00077     netsnmp_scalar_group *sgroup = (netsnmp_scalar_group *)handler->myvoid;
00078     int             ret, cmp;
00079     int             namelen;
00080     oid             subid, root_tmp[MAX_OID_LEN], *root_save;
00081 
00082     DEBUGMSGTL(("helper:scalar_group", "Got request:\n"));
00083     namelen = SNMP_MIN(requests->requestvb->name_length,
00084                        reginfo->rootoid_len);
00085     cmp = snmp_oid_compare(requests->requestvb->name, namelen,
00086                            reginfo->rootoid, reginfo->rootoid_len);
00087 
00088     DEBUGMSGTL(( "helper:scalar_group", "  cmp=%d, oid:", cmp));
00089     DEBUGMSGOID(("helper:scalar_group", var->name, var->name_length));
00090     DEBUGMSG((   "helper:scalar_group", "\n"));
00091 
00092     /*
00093      * copy root oid to root_tmp, set instance to 0. (subid set later on)
00094      * save rootoid, since we'll replace it before calling next handler,
00095      * and need to restore it afterwards.
00096      */
00097     memcpy(root_tmp, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
00098     root_tmp[reginfo->rootoid_len + 1] = 0;
00099     root_save = reginfo->rootoid;
00100 
00101     ret = SNMP_ERR_NOCREATION;
00102     switch (reqinfo->mode) {
00103     /*
00104      * The handling of "exact" requests is basically the same.
00105      * The only difference between GET and SET requests is the
00106      *     error/exception to return on failure.
00107      */
00108     case MODE_GET:
00109         ret = SNMP_NOSUCHOBJECT;
00110         /* Fallthrough */
00111 
00112 #ifndef NETSNMP_NO_WRITE_SUPPORT
00113     case MODE_SET_RESERVE1:
00114     case MODE_SET_RESERVE2:
00115     case MODE_SET_ACTION:
00116     case MODE_SET_COMMIT:
00117     case MODE_SET_UNDO:
00118     case MODE_SET_FREE:
00119         if (cmp != 0 ||
00120             requests->requestvb->name_length <= reginfo->rootoid_len) {
00121             /*
00122              * Common prefix doesn't match, or only *just* matches 
00123              *  the registered root (so can't possibly match a scalar)
00124              */
00125             netsnmp_set_request_error(reqinfo, requests, ret);
00126             return SNMP_ERR_NOERROR;
00127         } else {
00128             /*
00129              * Otherwise,
00130              *     extract the object subidentifier from the request, 
00131              *     check this is (probably) valid, and then fudge the
00132              *     registered 'rootoid' to match, before passing the
00133              *     request off to the next handler ('scalar').
00134              *
00135              * Note that we don't bother checking instance subidentifiers
00136              *     here.  That's left to the scalar helper.
00137              */
00138             subid = requests->requestvb->name[reginfo->rootoid_len];
00139             if (subid < sgroup->lbound ||
00140                 subid > sgroup->ubound) {
00141                 netsnmp_set_request_error(reqinfo, requests, ret);
00142                 return SNMP_ERR_NOERROR;
00143             }
00144             root_tmp[reginfo->rootoid_len] = subid;
00145             reginfo->rootoid_len += 2;
00146             reginfo->rootoid = root_tmp;
00147             ret = netsnmp_call_next_handler(handler, reginfo, reqinfo,
00148                                             requests);
00149             reginfo->rootoid = root_save;
00150             reginfo->rootoid_len -= 2;
00151             return ret;
00152         }
00153         break;
00154 #endif /* NETSNMP_NO_WRITE_SUPPORT */
00155 
00156     case MODE_GETNEXT:
00157         /*
00158          * If we're being asked for something before (or exactly matches)
00159          *     the registered root OID, then start with the first object.
00160          * If we're being asked for something that exactly matches an object
00161          *    OID, then that's what we pass down.
00162          * Otherwise, we pass down the OID of the *next* object....
00163          */
00164         if (cmp < 0 ||
00165             requests->requestvb->name_length <= reginfo->rootoid_len) {
00166             subid  = sgroup->lbound;
00167         } else if (requests->requestvb->name_length == reginfo->rootoid_len+1)
00168             subid = requests->requestvb->name[reginfo->rootoid_len];
00169         else
00170             subid = requests->requestvb->name[reginfo->rootoid_len]+1;
00171 
00172         /*
00173          * ... always assuming this is (potentially) valid, of course.
00174          */
00175         if (subid < sgroup->lbound)
00176             subid = sgroup->lbound;
00177         else if (subid > sgroup->ubound)
00178             return SNMP_ERR_NOERROR;
00179         
00180         root_tmp[reginfo->rootoid_len] = subid;
00181         reginfo->rootoid_len += 2;
00182         reginfo->rootoid = root_tmp;
00183         ret = netsnmp_call_next_handler(handler, reginfo, reqinfo,
00184                                             requests);
00185         /*
00186          * If we didn't get an answer (due to holes in the group)
00187          *   set things up to retry again.
00188          */
00189         if (!requests->delegated &&
00190             (requests->requestvb->type == ASN_NULL ||
00191              requests->requestvb->type == SNMP_NOSUCHOBJECT ||
00192              requests->requestvb->type == SNMP_NOSUCHINSTANCE)) {
00193             snmp_set_var_objid(requests->requestvb,
00194                                reginfo->rootoid, reginfo->rootoid_len - 1);
00195             requests->requestvb->name[reginfo->rootoid_len - 2] = ++subid;
00196             requests->requestvb->type = ASN_PRIV_RETRY;
00197         }
00198         reginfo->rootoid = root_save;
00199         reginfo->rootoid_len -= 2;
00200         return ret;
00201     }
00202     /*
00203      * got here only if illegal mode found 
00204      */
00205     return SNMP_ERR_GENERR;
00206 }
00207