Beispiel #1
0
int
TnmSnmpEncode(Tcl_Interp *interp, TnmSnmp *session, TnmSnmpPdu *pdu, TnmSnmpRequestProc *proc, ClientData clientData)
{
    int	retry = 0, packetlen = 0, code = 0;
    u_char packet[TNM_SNMP_MAXSIZE];
    TnmBer *ber;

    memset((char *) packet, 0, sizeof(packet));

    /*
     * Some special care must be taken to conform to SNMPv1 sessions:
     * SNMPv2 getbulk requests must be turned into getnext requests
     * and SNMPv2 error codes must be mapped on SNMPv1 error codes
     * (e.g. genErr as nothing more appropriate is available).
     *
     * This is based on the mapping presented in Marhall Rose and
     * Keith McCloghrie: "How to Manage your Network using SNMP"
     * page 95.
     */

    if (session->version == TNM_SNMPv1) {
        if (pdu->type == ASN1_SNMP_GETBULK) {
	    pdu->type = ASN1_SNMP_GETNEXT;
	    pdu->errorStatus = TNM_SNMP_NOERROR;
	    pdu->errorIndex  = 0;
	}
	if (pdu->type == ASN1_SNMP_INFORM || pdu->type == ASN1_SNMP_TRAP2) {
	    pdu->type = ASN1_SNMP_TRAP1;
	}
	if (pdu->errorStatus > TNM_SNMP_GENERR) {
	    switch (pdu->errorStatus) {
	      case TNM_SNMP_NOACCESS:
	      case TNM_SNMP_NOCREATION:
	      case TNM_SNMP_AUTHORIZATIONERROR:
	      case TNM_SNMP_NOTWRITABLE:
	      case TNM_SNMP_INCONSISTENTNAME:
		pdu->errorStatus = TNM_SNMP_NOSUCHNAME; break;
	      case TNM_SNMP_WRONGTYPE:
	      case TNM_SNMP_WRONGLENGTH:
	      case TNM_SNMP_WRONGENCODING:
	      case TNM_SNMP_WRONGVALUE:
	      case TNM_SNMP_INCONSISTENTVALUE:
		pdu->errorStatus = TNM_SNMP_BADVALUE; break;	
	      case TNM_SNMP_RESOURCEUNAVAILABLE:
	      case TNM_SNMP_COMMITFAILED:
	      case TNM_SNMP_UNDOFAILED:
		pdu->errorStatus = TNM_SNMP_GENERR; break;
	      default:
		pdu->errorStatus = TNM_SNMP_GENERR; break;
	    }
	}
    }

    /*
     * Encode message into ASN1 BER transfer syntax. Authentication or
     * encryption is done within the following procedures if it is an
     * authentic or private message.
     */

    ber = TnmBerCreate(packet, sizeof(packet));
    code = EncodeMessage(interp, session, pdu, ber);
    if (code != TCL_OK) {
	TnmBerDelete(ber);
	return TCL_ERROR;
    }
    packetlen = TnmBerSize(ber);
    TnmBerDelete(ber);

    switch (pdu->type) {
      case ASN1_SNMP_GET:
	  tnmSnmpStats.snmpOutGetRequests++;
	  break;
      case ASN1_SNMP_GETNEXT:
	  tnmSnmpStats.snmpOutGetNexts++;
	  break;
      case ASN1_SNMP_SET:
	  tnmSnmpStats.snmpOutSetRequests++;
	  break;
      case ASN1_SNMP_RESPONSE:
	  tnmSnmpStats.snmpOutGetResponses++;
	  break;
      case ASN1_SNMP_TRAP1:
	  tnmSnmpStats.snmpOutTraps++; 
	  break;
    }
    
    /*
     * Show the contents of the PDU - mostly for debugging.
     */
    
    TnmSnmpEvalBinding(interp, session, pdu, TNM_SNMP_SEND_EVENT);

    TnmSnmpDumpPDU(interp, pdu);

    /*
     * A trap message or a response? - send it and we are done!
     */
    
    if (pdu->type == ASN1_SNMP_TRAP1 || pdu->type == ASN1_SNMP_TRAP2 
	|| pdu->type == ASN1_SNMP_RESPONSE || pdu->type == ASN1_SNMP_REPORT) {
#ifdef TNM_SNMPv2U
	if (session->version == TNM_SNMPv2U) {
	    TnmSnmpUsecAuth(session, packet, packetlen);
	}
#endif
	code = TnmSnmpSend(interp, session, packet, packetlen,
			   &pdu->addr, TNM_SNMP_ASYNC);
	if (code != TCL_OK) {
	    return TCL_ERROR;
	}
	Tcl_ResetResult(interp);
	return TCL_OK;
    }
  
    /*
     * Asychronous request: queue request and we are done.
     */

    if (proc) {
	TnmSnmpRequest *rPtr;
	rPtr = TnmSnmpCreateRequest(pdu->requestId, packet, packetlen,
				    proc, clientData, interp);
	TnmSnmpQueueRequest(session, rPtr);
	Tcl_SetObjResult (interp, Tcl_NewIntObj (pdu->requestId));
	return TCL_OK;
    }
    
    /*
     * Synchronous request: send packet and wait for response.
     */
    
    for (retry = 0; retry <= session->retries; retry++) {
	int id, status, index;
#ifdef TNM_SNMP_BENCH
	TnmSnmpMark stats;
	memset((char *) &stats, 0, sizeof(stats));
#endif

      repeat:
#ifdef TNM_SNMPv2U
	if (session->version == TNM_SNMPv2U) {
	    TnmSnmpUsecAuth(session, packet, packetlen);
	}
#endif
	TnmSnmpDelay(session);
	code = TnmSnmpSend(interp, session, packet, packetlen, 
			   &pdu->addr, TNM_SNMP_SYNC);
	if (code != TCL_OK) {
	    return TCL_ERROR;
	}

#ifdef TNM_SNMP_BENCH
	if (stats.sendSize == 0) {
	    stats.sendSize = tnmSnmpBenchMark.sendSize;
	    stats.sendTime = tnmSnmpBenchMark.sendTime;
	}
#endif

	while (TnmSnmpWait(session->timeout * 1000
			   / (session->retries + 1), TNM_SNMP_SYNC) > 0) {
	    u_char packet[TNM_SNMP_MAXSIZE];
	    int rc, packetlen = TNM_SNMP_MAXSIZE;
	    struct sockaddr_in from;

	    code = TnmSnmpRecv(interp, packet, &packetlen, 
			       &from, TNM_SNMP_SYNC);
	    if (code != TCL_OK) {
		return TCL_ERROR;
	    }
	    
	    rc = TnmSnmpDecode(interp, packet, packetlen, &from,
			       session, &id, &status, &index);
	    if (rc == TCL_BREAK) {
		if (retry++ <= session->retries + 1) {
		    goto repeat;
		}
	    }
	    if (rc == TCL_OK) {
		if (id == pdu->requestId) {
#ifdef TNM_SNMP_BENCH
		    stats.recvSize = tnmSnmpBenchMark.recvSize;
		    stats.recvTime = tnmSnmpBenchMark.recvTime;
		    session->stats = stats;
#endif
		    return TCL_OK;
		}
		rc = TCL_CONTINUE;
	    }
	    
	    if (rc == TCL_CONTINUE) {
		if (hexdump) {
		    fprintf(stderr, "%s\n", Tcl_GetStringResult(interp));
		}
		continue;
	    }
	    if (rc == TCL_ERROR) {
		pdu->errorStatus = status;
		pdu->errorIndex = index;
		return TCL_ERROR;
	    }
	}
    }
    
    Tcl_SetResult(interp, "noResponse 0 {}", TCL_STATIC);
    return TCL_ERROR;
}
Beispiel #2
0
void
TnmSnmpDeleteRequest(TnmSnmpRequest *request)
{
    TnmSnmpRequest *rPtr, **rPtrPtr;
    TnmSnmp *session;

    /*
     * Check whether the request still exists. It may have been
     * removed because the session for this request has been 
     * destroyed during callback processing.
     */

    for (rPtr = queueHead; rPtr; rPtr = rPtr->nextPtr) {
	if (rPtr == request) break;
    }
    if (! rPtr) return;
    
    /* 
     * Check whether the session is still in the session list.
     * We sometimes get called when the session has already been
     * destroyed as a side effect of evaluating callbacks.
     */
    
    for (session = tnmSnmpList; session; session = session->nextPtr) {
	if (session == request->session) break;
    }

    if (session) {
	if (request->sends) {
	    session->active--;
	} else {
	    session->waiting--;
	}
    }
    
    /*
     * Remove the request from the list of outstanding requests.
     * and free the resources allocated for this request.
     */

    rPtrPtr = &queueHead;
    while (*rPtrPtr && *rPtrPtr != request) {
	rPtrPtr = &(*rPtrPtr)->nextPtr;
    }
    if (*rPtrPtr) {
	*rPtrPtr = request->nextPtr;
	if (request->timer) {
	    Tcl_DeleteTimerHandler(request->timer);
	    request->timer = NULL;
	}
	Tcl_EventuallyFree((ClientData) request, RequestDestroyProc);
    }

    /*
     * Update the request queue. This will activate async requests
     * that have been queued because of the window size.
     */
     
    if (session) {
	TnmSnmpQueueRequest(session, NULL);
    }
}