Exemple #1
0
//********************************************************************************
//********************************************************************************
static void delayed_response(unsigned int clientreg, void * clientarg)
{
    syslog(LOG_DEBUG, "Enter: delayed_response, %s.", HANDLER_NAME); 

    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) clientarg;
    if(!netsnmp_handler_check_cache(cache))
    {
        syslog(LOG_ERR, "%s", "illegal call to return delayed response.");
        return;
    }
    syslog(LOG_DEBUG, "delayed_instance, continuing delayed request, mode = %d.",
        cache->reqinfo->mode);

    cache->requests->delegated = 0;

    switch(cache->reqinfo->mode)
    {
        case MODE_GET:
        case MODE_GETNEXT:
        int32_t redirect = redirect_count();
        snmp_set_var_typed_integer(cache->requests->requestvb,
            ASN_COUNTER, redirect);
    }
    netsnmp_free_delegated_cache(cache);

    syslog(LOG_DEBUG, "Exit: delayed_response, %s.", HANDLER_NAME); 
    syslog(LOG_DEBUG,"%s",
        "===============================================================");
    return;
}
void
return_delayed_response(unsigned int clientreg, void *clientarg)
{
    /*
     * extract the cache from the passed argument 
     */
    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) clientarg;

    netsnmp_request_info *requests;
    netsnmp_agent_request_info *reqinfo;
    u_long         *delay_time_cache = NULL;

    /*
     * here we double check that the cache we created earlier is still
     * * valid.  If not, the request timed out for some reason and we
     * * don't need to keep processing things.  Should never happen, but
     * * this double checks. 
     */
    cache = netsnmp_handler_check_cache(cache);

    if (!cache) {
        snmp_log(LOG_ERR, "illegal call to return delayed response\n");
        return;
    }

    /*
     * re-establish the previous pointers we are used to having 
     */
    reqinfo = cache->reqinfo;
    requests = cache->requests;

    DEBUGMSGTL(("delayed_instance",
                "continuing delayed request, mode = %d\n",
                cache->reqinfo->mode));

    /*
     * mention that it's no longer delegated, and we've now answered
     * the query (which we'll do down below). 
     */
    requests->delegated = 0;

    switch (cache->reqinfo->mode) {
        /*
         * registering as an instance means we don't need to deal with
         * getnext processing, so we don't handle it here at all.
         * 
         * However, since the instance handler already reset the mode
         * back to GETNEXT from the faked GET mode, we need to do the
         * same thing in both cases.  This should be fixed in future
         * versions of net-snmp hopefully. 
         */

    case MODE_GET:
    case MODE_GETNEXT:
        /*
         * return the currend delay time 
         */
        snmp_set_var_typed_value(cache->requests->requestvb,
                                 ASN_INTEGER,
                                 (u_char *) & delay_time,
                                 sizeof(delay_time));
        break;

#ifndef NETSNMP_NO_WRITE_SUPPORT
    case MODE_SET_RESERVE1:
        /*
         * check type 
         */
        if (requests->requestvb->type != ASN_INTEGER) {
            /*
             * not an integer.  Bad dog, no bone. 
             */
            netsnmp_set_request_error(reqinfo, requests,
                                      SNMP_ERR_WRONGTYPE);
            /*
             * we don't need the cache any longer 
             */
            netsnmp_free_delegated_cache(cache);
            return;
        }
        break;

    case MODE_SET_RESERVE2:
        /*
         * store old value for UNDO support in the future. 
         */
        delay_time_cache = netsnmp_memdup(&delay_time, sizeof(delay_time));

        /*
         * malloc failed 
         */
        if (delay_time_cache == NULL) {
            netsnmp_set_request_error(reqinfo, requests,
                                      SNMP_ERR_RESOURCEUNAVAILABLE);
            netsnmp_free_delegated_cache(cache);
            return;
        }

        /*
         * Add our temporary information to the request itself.
         * This is then retrivable later.  The free function
         * passed auto-frees it when the request is later
         * deleted.  
         */
        netsnmp_request_add_list_data(requests,
                                      netsnmp_create_data_list
                                      (DELAYED_INSTANCE_SET_NAME,
                                       delay_time_cache, free));
        break;

    case MODE_SET_ACTION:
        /*
         * update current value 
         */
        delay_time = *(requests->requestvb->val.integer);
        DEBUGMSGTL(("testhandler", "updated delay_time -> %ld\n",
                    delay_time));
        break;

    case MODE_SET_UNDO:
        /*
         * ack, something somewhere failed.  We reset back to the
         * previously old value by extracting the previosuly
         * stored information back out of the request 
         */
        delay_time =
            *((u_long *) netsnmp_request_get_list_data(requests,
                                                       DELAYED_INSTANCE_SET_NAME));
        break;

    case MODE_SET_COMMIT:
    case MODE_SET_FREE:
        /*
         * the only thing to do here is free the old memdup'ed
         * value, but it's auto-freed by the datalist recovery, so
         * we don't have anything to actually do here 
         */
        break;
#endif /* NETSNMP_NO_WRITE_SUPPORT */
    }

    /*
     * free the information cache 
     */
    netsnmp_free_delegated_cache(cache);
}
        /*
         * Handle the response from an AgentX subagent,
         *   merging the answers back into the original query
         */
int
agentx_got_response(int operation,
                    netsnmp_session * session,
                    int reqid, netsnmp_pdu *pdu, void *magic)
{
    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) magic;
    int             i, ret;
    netsnmp_request_info *requests, *request;
    netsnmp_variable_list *var;
    netsnmp_session *ax_session;

    cache = netsnmp_handler_check_cache(cache);
    if (!cache) {
        DEBUGMSGTL(("agentx/master", "response too late on session %8p\n",
                    session));
        return 0;
    }
    requests = cache->requests;

    switch (operation) {
    case NETSNMP_CALLBACK_OP_TIMED_OUT:{
            void           *s = snmp_sess_pointer(session);
            DEBUGMSGTL(("agentx/master", "timeout on session %8p\n",
                        session));

            netsnmp_handler_mark_requests_as_delegated(requests,
                                       REQUEST_IS_NOT_DELEGATED);
            netsnmp_set_request_error(cache->reqinfo, requests,
                                      /* XXXWWW: should be index=0 */
                                      SNMP_ERR_GENERR);

            /*
             * This is a bit sledgehammer because the other sessions on this
             * transport may be okay (e.g. some thread in the subagent has
             * wedged, but the others are alright).  OTOH the overwhelming
             * probability is that the whole agent has died somehow.  
             */

            if (s != NULL) {
                netsnmp_transport *t = snmp_sess_transport(s);
                close_agentx_session(session, -1);

                if (t != NULL) {
                    DEBUGMSGTL(("agentx/master", "close transport\n"));
                    t->f_close(t);
                } else {
                    DEBUGMSGTL(("agentx/master", "NULL transport??\n"));
                }
            } else {
                DEBUGMSGTL(("agentx/master", "NULL sess_pointer??\n"));
            }
            ax_session = (netsnmp_session *) cache->localinfo;
            netsnmp_free_agent_snmp_session_by_session(ax_session, NULL);
            netsnmp_free_delegated_cache(cache);
            return 0;
        }

    case NETSNMP_CALLBACK_OP_DISCONNECT:
    case NETSNMP_CALLBACK_OP_SEND_FAILED:
        if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
            DEBUGMSGTL(("agentx/master", "disconnect on session %8p\n",
                        session));
        } else {
            DEBUGMSGTL(("agentx/master", "send failed on session %8p\n",
                        session));
        }
        close_agentx_session(session, -1);
        netsnmp_handler_mark_requests_as_delegated(requests,
                                                   REQUEST_IS_NOT_DELEGATED);
        netsnmp_set_request_error(cache->reqinfo, requests,     /* XXXWWW: should be index=0 */
                                  SNMP_ERR_GENERR);
        netsnmp_free_delegated_cache(cache);
        return 0;

    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
        /*
         * This session is alive 
         */
        CLEAR_SNMP_STRIKE_FLAGS(session->flags);
        break;
    default:
        snmp_log(LOG_ERR, "Unknown operation %d in agentx_got_response\n",
                 operation);
        netsnmp_free_delegated_cache(cache);
        return 0;
    }

    DEBUGMSGTL(("agentx/master", "got response errstat=%ld, (req=0x%x,trans="
                "0x%x,sess=0x%x)\n",
                pdu->errstat, (unsigned)pdu->reqid, (unsigned)pdu->transid,
		(unsigned)pdu->sessid));

    if (pdu->errstat != AGENTX_ERR_NOERROR) {
        /* [RFC 2471 - 7.2.5.2.]
         *
         *   1) For any received AgentX response PDU, if res.error is
         *      not `noError', the SNMP response PDU's error code is
         *      set to this value.  If res.error contains an AgentX
         *      specific value (e.g.  `parseError'), the SNMP response
         *      PDU's error code is set to a value of genErr instead.
         *      Also, the SNMP response PDU's error index is set to
         *      the index of the variable binding corresponding to the
         *      failed VarBind in the subagent's AgentX response PDU.
         *
         *      All other AgentX response PDUs received due to
         *      processing this SNMP request are ignored.  Processing
         *      is complete; the SNMP Response PDU is ready to be sent
         *      (see section 7.2.6, "Sending the SNMP Response-PDU").
         */
        int err;

        DEBUGMSGTL(("agentx/master",
                    "agentx_got_response() error branch\n"));

        switch (pdu->errstat) {
        case AGENTX_ERR_PARSE_FAILED:
        case AGENTX_ERR_REQUEST_DENIED:
        case AGENTX_ERR_PROCESSING_ERROR:
            err = SNMP_ERR_GENERR;
            break;
        default:
            err = pdu->errstat;
        }

        ret = 0;
        for (request = requests, i = 1; request;
             request = request->next, i++) {
            if (i == pdu->errindex) {
                /*
                 * Mark this varbind as the one generating the error.
                 * Note that the AgentX errindex may not match the
                 * position in the original SNMP PDU (request->index)
                 */
                netsnmp_set_request_error(cache->reqinfo, request,
                                          err);
                ret = 1;
            }
            request->delegated = REQUEST_IS_NOT_DELEGATED;
        }
        if (!ret) {
            /*
             * ack, unknown, mark the first one
             */
            netsnmp_set_request_error(cache->reqinfo, requests,
                                      SNMP_ERR_GENERR);
        }
        netsnmp_free_delegated_cache(cache);
        DEBUGMSGTL(("agentx/master", "end error branch\n"));
        return 1;
    } else if (cache->reqinfo->mode == MODE_GET ||
               cache->reqinfo->mode == MODE_GETNEXT ||
               cache->reqinfo->mode == MODE_GETBULK) {
        /*
         * Replace varbinds for data request types, but not SETs.  
         */
        DEBUGMSGTL(("agentx/master",
                    "agentx_got_response() beginning...\n"));
        for (var = pdu->variables, request = requests; request && var;
             request = request->next, var = var->next_variable) {
            /*
             * Otherwise, process successful requests
             */
            DEBUGMSGTL(("agentx/master",
                        "  handle_agentx_response: processing: "));
            DEBUGMSGOID(("agentx/master", var->name, var->name_length));
            DEBUGMSG(("agentx/master", "\n"));
            if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE)) {
                DEBUGMSGTL(("snmp_agent", "    >> "));
                DEBUGMSGVAR(("snmp_agent", var));
                DEBUGMSG(("snmp_agent", "\n"));
            }

            /*
             * update the oid in the original request 
             */
            if (var->type != SNMP_ENDOFMIBVIEW) {
                snmp_set_var_typed_value(request->requestvb, var->type,
                                         var->val.string, var->val_len);
                snmp_set_var_objid(request->requestvb, var->name,
                                   var->name_length);
            }
            request->delegated = REQUEST_IS_NOT_DELEGATED;
        }

        if (request || var) {
            /*
             * ack, this is bad.  The # of varbinds don't match and
             * there is no way to fix the problem 
             */
            snmp_log(LOG_ERR,
                     "response to agentx request illegal.  bailing out.\n");
            netsnmp_set_request_error(cache->reqinfo, requests,
                                      SNMP_ERR_GENERR);
        }

        if (cache->reqinfo->mode == MODE_GETBULK)
            netsnmp_bulk_to_next_fix_requests(requests);
    } else {
        /*
         * mark set requests as handled 
         */
        for (request = requests; request; request = request->next) {
            request->delegated = REQUEST_IS_NOT_DELEGATED;
        }
    }
    DEBUGMSGTL(("agentx/master",
                "handle_agentx_response() finishing...\n"));
    netsnmp_free_delegated_cache(cache);
    return 1;
}
Exemple #4
0
int
proxy_got_response(int operation, netsnmp_session * sess, int reqid,
                   netsnmp_pdu *pdu, void *cb_data)
{
    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data;
    netsnmp_request_info  *requests, *request = NULL;
    netsnmp_variable_list *vars,     *var     = NULL;

    struct simple_proxy *sp;
    oid             myname[MAX_OID_LEN];
    size_t          myname_len = MAX_OID_LEN;

    cache = netsnmp_handler_check_cache(cache);

    if (!cache) {
        DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
        return SNMP_ERR_NOERROR;
    }

    requests = cache->requests;


    sp = (struct simple_proxy *) cache->localinfo;

    if (!sp) {
        DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
        return SNMP_ERR_NOERROR;
    }

    switch (operation) {
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
        /*
         * WWWXXX: don't leave requests delayed if operation is
         * something like TIMEOUT 
         */
        DEBUGMSGTL(("proxy", "got timed out... requests = %08p\n", requests));

        netsnmp_handler_mark_requests_as_delegated(requests,
                                                   REQUEST_IS_NOT_DELEGATED);
        if(cache->reqinfo->mode != MODE_GETNEXT) {
            DEBUGMSGTL(("proxy", "  ignoring timeout\n"));
            netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index = 0 */
                                      SNMP_ERR_GENERR);
        }
        netsnmp_free_delegated_cache(cache);
        return 0;

    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
        vars = pdu->variables;

        if (pdu->errstat != SNMP_ERR_NOERROR) {
            /*
             *  If we receive an error from the proxy agent, pass it on up.
             *  The higher-level processing seems to Do The Right Thing.
             *
             * 2005/06 rks: actually, it doesn't do the right thing for
             * a get-next request that returns NOSUCHNAME. If we do nothing,
             * it passes that error back to the comman initiator. What it should
             * do is ignore the error and move on to the next tree. To
             * accomplish that, all we need to do is clear the delegated flag.
             * Not sure if any other error codes need the same treatment. Left
             * as an exercise to the reader...
             */
            DEBUGMSGTL(("proxy", "got error response (%d)\n", pdu->errstat));
            if((cache->reqinfo->mode == MODE_GETNEXT) &&
               (SNMP_ERR_NOSUCHNAME == pdu->errstat)) {
                DEBUGMSGTL(("proxy", "  ignoring error response\n"));
                netsnmp_handler_mark_requests_as_delegated(requests,
                                                           REQUEST_IS_NOT_DELEGATED);
            }
            else
                netsnmp_set_request_error(cache->reqinfo, requests, pdu->errstat);

        /*
         * update the original request varbinds with the results 
         */
	} else for (var = vars, request = requests;
             request && var;
             request = request->next, var = var->next_variable) {
            /*
             * XXX - should this be done here?
             *       Or wait until we know it's OK?
             */
            snmp_set_var_typed_value(request->requestvb, var->type,
                                     var->val.string, var->val_len);

            DEBUGMSGTL(("proxy", "got response... "));
            DEBUGMSGOID(("proxy", var->name, var->name_length));
            DEBUGMSG(("proxy", "\n"));
            request->delegated = 0;

            /*
             * Check the response oid is legitimate,
             *   and discard the value if not.
             *
             * XXX - what's the difference between these cases?
             */
            if (sp->base_len &&
                (var->name_length < sp->base_len ||
                 snmp_oid_compare(var->name, sp->base_len, sp->base,
                                  sp->base_len) != 0)) {
                DEBUGMSGTL(( "proxy", "out of registered range... "));
                DEBUGMSGOID(("proxy", var->name, sp->base_len));
                DEBUGMSG((   "proxy", " (%d) != ", sp->base_len));
                DEBUGMSGOID(("proxy", sp->base, sp->base_len));
                DEBUGMSG((   "proxy", "\n"));
                snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0);

                continue;
            } else if (!sp->base_len &&
                       (var->name_length < sp->name_len ||
                        snmp_oid_compare(var->name, sp->name_len, sp->name,
                                         sp->name_len) != 0)) {
                DEBUGMSGTL(( "proxy", "out of registered base range... "));
                DEBUGMSGOID(("proxy", var->name, sp->name_len));
                DEBUGMSG((   "proxy", " (%d) != ", sp->name_len));
                DEBUGMSGOID(("proxy", sp->name, sp->name_len));
                DEBUGMSG((   "proxy", "\n"));
                snmp_set_var_typed_value(request->requestvb, ASN_NULL, NULL, 0);
                continue;
            } else {
                /*
                 * If the returned OID is legitimate, then update
                 *   the original request varbind accordingly.
                 */
                if (sp->base_len) {
                    /*
                     * XXX: oid size maxed? 
                     */
                    memcpy(myname, sp->name, sizeof(oid) * sp->name_len);
                    myname_len =
                        sp->name_len + var->name_length - sp->base_len;
                    if (myname_len > MAX_OID_LEN) {
                        snmp_log(LOG_WARNING,
                                 "proxy OID return length too long.\n");
                        netsnmp_set_request_error(cache->reqinfo, requests,
                                                  SNMP_ERR_GENERR);
                        if (pdu)
                            snmp_free_pdu(pdu);
                        netsnmp_free_delegated_cache(cache);
                        return 1;
                    }

                    if (var->name_length > sp->base_len)
                        memcpy(&myname[sp->name_len],
                               &var->name[sp->base_len],
                               sizeof(oid) * (var->name_length -
                                              sp->base_len));
                    snmp_set_var_objid(request->requestvb, myname,
                                       myname_len);
                } else {
                    snmp_set_var_objid(request->requestvb, var->name,
                                       var->name_length);
                }
            }
        }

        if (request || var) {
            /*
             * ack, this is bad.  The # of varbinds don't match and
             * there is no way to fix the problem 
             */
            if (pdu)
                snmp_free_pdu(pdu);
            snmp_log(LOG_ERR,
                     "response to proxy request illegal.  We're screwed.\n");
            netsnmp_set_request_error(cache->reqinfo, requests,
                                      SNMP_ERR_GENERR);
        }

        /* fix bulk_to_next operations */
        if (cache->reqinfo->mode == MODE_GETBULK)
            netsnmp_bulk_to_next_fix_requests(requests);
        
        /*
         * free the response 
         */
        if (pdu && 0)
            snmp_free_pdu(pdu);
	break;

    default:
        DEBUGMSGTL(("proxy", "no response received: op = %d\n",
                    operation));
	break;
    }

    netsnmp_free_delegated_cache(cache);
    return 1;
}
void
get_status(unsigned int clientreg, void *clientarg)
{
  /*
   * This function returns the value of the status variable.
   * If the value of status is 0 (no collection is running), it
   * calles collect_data to start one.
   *  
   */
	
  /*
   * Extract the cache from the passed argument.
   */
    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) clientarg;
    netsnmp_request_info *requests;
    netsnmp_agent_request_info *reqinfo;
    u_long         *delay_time_cache = NULL;

    /*
     * Make sure the cache created earlier is still
     * valid.  If not, the request timed out for some reason and we
     * do not need to keep processing things.  Should never happen, but
     * this double checks. 
     */
    cache = netsnmp_handler_check_cache(cache);

    if (!cache) {
        snmp_log(LOG_ERR, "illegal call to return delayed response\n");
        return;
    }

    /*
     * Re-establish the previous pointers,
     */
    reqinfo = cache->reqinfo;
    requests = cache->requests;

    DEBUGMSGTL(("demo_module_10",
                "continuing delayed request, mode = %d\n",
                cache->reqinfo->mode));
    
    /*
     * Set delegated to zero to indicate that the request is no longer
     * delegated and answer the query.
     */
    requests->delegated = 0;

    switch (cache->reqinfo->mode) {
        /*
         * Registering as an instance means we do not need to deal with
         * GETNEXT processing, so we do not handle it here at all.
         * 
         * However, since the instance handler already reset the mode
         * back to GETNEXT from the GET mode, we need to do the
         * same thing in both cases.
	 *
         */
	case MODE_GET:
            // no collection running, start one.
	    if (status == 0)
		    collect_data();
	    snmp_set_var_typed_value(requests->requestvb,
	        ASN_INTEGER, (u_char *) & status,
		    sizeof (status) /* length in bytes */);
		break;
	case MODE_SET_RESERVE1:
	    /*
	     * check type 
	     */
	    if (requests->requestvb->type != ASN_INTEGER) {
		    /*
		     * If not an integer, return SNMP error. 
		     */
		    netsnmp_set_request_error(reqinfo, requests,
                                      SNMP_ERR_WRONGTYPE);
		    /*
		     * Free cache. It is no longer needed. 
		     */
		    netsnmp_free_delegated_cache(cache);
		    return;
	    }
	    break;
   	case MODE_SET_RESERVE2:
		    /*
		     * Store old value for UNDO support in the future. 
		     */
		    memdup((u_char **) & delay_time_cache,
			(u_char *) & delay_time, sizeof(delay_time));

		    /*
		     * malloc failed 
		     */
		    if (delay_time_cache == NULL) {
			    netsnmp_set_request_error(reqinfo, requests,
                                      SNMP_ERR_RESOURCEUNAVAILABLE);
			    netsnmp_free_delegated_cache(cache);
			    return;
		    }

		    /*
		     * Add our temporary information to the request itself.
		     * This is then retrivable later.  The free function
		     * passed auto-frees it when the request is later
		     * deleted.  
		     */
		    netsnmp_request_add_list_data(requests,
                                      netsnmp_create_data_list
                                      (DELAYED_INSTANCE_SET_NAME,
                                       delay_time_cache, free));
		    break;
	case MODE_SET_ACTION:
		// get status integer from request
		// if status == 0, start data collection, else return error
		if (*(requests->requestvb->val.integer) == 0) {
			status = *(requests->requestvb->val.integer);
		        collect_data();
		} else
			netsnmp_set_request_error(reqinfo, requests,
			    SNMP_ERR_WRONGTYPE);
		break;
	case MODE_SET_UNDO:
	    /*
	     * A failure occurred. Reset to the
	     * previously value by extracting the previosuly
	     * stored information from the request.
	     */
	    delay_time =
		*((u_long *) netsnmp_request_get_list_data(requests,
                                                       DELAYED_INSTANCE_SET_NAME));
	    break;
	case MODE_SET_COMMIT:
		break;
	case MODE_SET_FREE:
	    /*
	     * The only thing to do here is free the old memdup'ed
	     * value, but it's auto-freed by the datalist recovery, so
	     * we don't have anything to actually do here 
	     */
	    break;
    }

    /*
     * free the information cache 
     */
    netsnmp_free_delegated_cache(cache);
		
}
Exemple #6
0
int
proxy_got_response(int operation, netsnmp_session * sess, int reqid,
                   netsnmp_pdu *pdu, void *cb_data)
{
    netsnmp_delegated_cache *cache = (netsnmp_delegated_cache *) cb_data;
    netsnmp_request_info *requests, *request;
    netsnmp_variable_list *vars, *var;

    struct simple_proxy *sp;
    oid             myname[MAX_OID_LEN];
    size_t          myname_len = MAX_OID_LEN;

    cache = netsnmp_handler_check_cache(cache);

    if (!cache) {
        DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
        return SNMP_ERR_NOERROR;
    }

    requests = cache->requests;


    sp = (struct simple_proxy *) cache->localinfo;

    if (!sp) {
        DEBUGMSGTL(("proxy", "a proxy request was no longer valid.\n"));
        return SNMP_ERR_NOERROR;
    }

    switch (operation) {
    case NETSNMP_CALLBACK_OP_TIMED_OUT:
        /*
         * WWWXXX: don't leave requests delayed if operation is
         * something like TIMEOUT 
         */
        DEBUGMSGTL(("proxy", "got timed out... requests = %08p\n", requests));

        netsnmp_handler_mark_requests_as_delegated(requests,
						   REQUEST_IS_NOT_DELEGATED);
        netsnmp_set_request_error(cache->reqinfo, requests, /* XXXWWW: should be index = 0 */
				  SNMP_ERR_GENERR);
        netsnmp_free_delegated_cache(cache);
        return 0;

    case NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE:
        vars = pdu->variables;

        /*
         * update the original request varbinds with the results 
         */
        for (var = vars, request = requests;
             request && var;
             request = request->next, var = var->next_variable) {
            snmp_set_var_typed_value(request->requestvb, var->type,
                                     var->val.string, var->val_len);

            DEBUGMSGTL(("proxy", "got response... "));
            DEBUGMSGOID(("proxy", var->name, var->name_length));
            DEBUGMSG(("proxy", "\n"));
            request->delegated = 0;

            /*
             * copy the oid it belongs to 
             */
            if (sp->base_len &&
                (var->name_length < sp->base_len ||
                 snmp_oid_compare(var->name, sp->base_len, sp->base,
                                  sp->base_len) != 0)) {
                DEBUGMSGTL(("proxy", "out of registered range... "));
                DEBUGMSGOID(("proxy", var->name, sp->base_len));
                DEBUGMSG(("proxy", " (%d) != ", sp->base_len));
                DEBUGMSGOID(("proxy", sp->base, sp->base_len));
                DEBUGMSG(("proxy", "\n"));

                continue;
            } else if (!sp->base_len &&
                       (var->name_length < sp->name_len ||
                        snmp_oid_compare(var->name, sp->name_len, sp->name,
                                         sp->name_len) != 0)) {
                DEBUGMSGTL(("proxy", "out of registered base range...\n"));
                /*
                 * or not if its out of our search range 
                 */
                continue;
            } else {
                if (sp->base_len) {
                    /*
                     * XXX: oid size maxed? 
                     */
                    memcpy(myname, sp->name, sizeof(oid) * sp->name_len);
                    myname_len =
                        sp->name_len + var->name_length - sp->base_len;
                    if (myname_len > MAX_OID_LEN) {
                        snmp_log(LOG_WARNING,
                                 "proxy OID return length too long.\n");
                        netsnmp_set_request_error(cache->reqinfo, requests,
                                                  SNMP_ERR_GENERR);
                        if (pdu)
                            snmp_free_pdu(pdu);
                        netsnmp_free_delegated_cache(cache);
                        return 1;
                    }

                    if (var->name_length > sp->base_len)
                        memcpy(&myname[sp->name_len],
                               &var->name[sp->base_len],
                               sizeof(oid) * (var->name_length -
                                              sp->base_len));
                    snmp_set_var_objid(request->requestvb, myname,
                                       myname_len);
                } else {
                    snmp_set_var_objid(request->requestvb, var->name,
                                       var->name_length);
                }
            }
        }

        if (request || var) {
            /*
             * ack, this is bad.  The # of varbinds don't match and
             * there is no way to fix the problem 
             */
            if (pdu)
                snmp_free_pdu(pdu);
            snmp_log(LOG_ERR,
                     "response to proxy request illegal.  We're screwed.\n");
            netsnmp_set_request_error(cache->reqinfo, requests,
                                      SNMP_ERR_GENERR);
        }

        /* fix bulk_to_next operations */
        if (cache->reqinfo->mode == MODE_GETBULK)
            netsnmp_bulk_to_next_fix_requests(requests);
        
        /*
         * free the response 
         */
        if (pdu && 0)
            snmp_free_pdu(pdu);
	break;

    default:
        DEBUGMSGTL(("proxy", "no response received: op = %d\n",
                    operation));
	break;
    }

    netsnmp_free_delegated_cache(cache);
    return 1;
}