/***************************************************************************/ /* Module: $Id: snmp.c,v 1.2 1999/05/07 04:15:26 maf Exp $ /* Description: OSU snmpclient module (high level) /* Author: maf /* Notes: /***************************************************************************/ /* $Log: snmp.c,v $ Revision 1.2 1999/05/07 04:15:26 maf pr -e2 Revision 1.1 1997/02/23 18:05:09 maf Initial revision * Revision 2.4 1994/05/09 13:26:55 maf * increased retransmission count * * Revision 2.3 1994/04/04 15:25:05 maf * *** empty log message *** * * Revision 2.2 1994/02/04 21:35:13 maf * *** empty log message *** * * Revision 2.1 1994/01/02 20:03:14 maf * mem dealloc bug, all requests with NULL object * * Revision 1.1 1993/12/20 01:50:47 maf * Initial revision * */ #include #include "snmp.h" #include "snmpcli.h" #ifdef SOCKET #include #include #include #include #include #include #endif /* SOCKET */ /* global */ int SNMPErrno; /*********************************************************************/ /* Function: SNMPConnect /* /* Description: /* Make initial connection to remote snmp host. /* /* Returns: 0 for good /* !0 for bad /* /* if bad, will set SNMPErrno /*********************************************************************/ int SNMPConnect(sc, hostname, community, maxrequests) struct SNMPConnection *sc; char *hostname, *community; int maxrequests; { extern int debug; #ifdef SOCKET struct hostent *hostptr; struct in_addr tmpaddr; struct sockaddr_in cli_addr, serv_addr; #endif extern int SNMPErrno; int err; err = 1; /* bad */ sc->IP = 0; sc->req = NULL; sc->reqr = NULL; sc->buffer = NULL; sc->community = NULL; sc->hostname = NULL; sc->validsocket = 0; #ifdef WATTCP sc->s = NULL; #endif /* WATTCP */ #ifdef DEBUG if (debug > 3) fprintf(stderr, "SNMPConnect: hn=%s c=%s mr=%d\n", hostname, community, maxrequests); #endif /* DEBUG */ if (!(sc->hostname = (char*)malloc(strlen(hostname)+1))) { SNMPErrno = SNMPE_MEMHNAME; goto SNMPConnectout; } strcpy(sc->hostname, hostname); if (!(sc->community = (char*)malloc(strlen(community)+1))) { SNMPErrno = SNMPE_MEMCOMMUNITY; goto SNMPConnectout; } strcpy(sc->community, community); #ifdef WATTCP if (!(sc->s = (tcp_Socket*) malloc(sizeof(tcp_Socket)))) { SNMPErrno = SNMPE_MEMSOCK; goto SNMPConnectout; } #endif /* allocate memory for snmp send/receive pkts */ if (!(sc->buffer = (char*)malloc(SNMP_PKT_MAX))) { SNMPErrno = SNMPE_MEMBUF; goto SNMPConnectout; } /* get mem for snmp request structure with number objects maxrequests */ if (!(sc->req = snmpEncodeNew((short)maxrequests))) { SNMPErrno = SNMPE_MEMREQUEST; goto SNMPConnectout; } /* get memory for snmp decode with maxrequests objects */ if (!(sc->reqr = snmpDecodeNew((short)maxrequests,(short)SNMP_PKT_MAX))){ SNMPErrno = SNMPE_MEMDECODE; goto SNMPConnectout; } #ifdef WATTCP /* resolve the host name */ #ifdef NETSTAT NetStatus(NETSTAT_RESOLVING); #endif /* NETSTAT */ if (!(sc->IP = resolve(hostname))) { SNMPErrno = SNMPE_RES; #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ goto SNMPConnectout; } #ifdef NETSTAT NetStatus(NETSTAT_NONE); NetStatus(NETSTAT_OPENING); #endif /* NETSTAT */ #ifdef DEBUG if (debug > 3) fprintf(stderr, "SNMPConnect: calling udp_open()\n"); #endif /* DEBUG */ /* Open a UDP socket to our SNMP host */ if (!udp_open(sc->s, 0, sc->IP, SNMP_PORT, NULL )){ SNMPErrno = SNMPE_CONNECT; #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ goto SNMPConnectout; } #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ #ifdef DEBUG if (debug > 3) fprintf(stderr, "SNMPConnect: past udp_open\n"); #endif /* DEBUG */ #endif /* WATTCP */ #ifdef SOCKET /* resolve the host name */ if (atoi(hostname)) { sc->IP = tmpaddr.s_addr = inet_addr(hostname); } else { if ((hostptr = gethostbyname(hostname)) == NULL) { SNMPErrno = SNMPE_RES; goto SNMPConnectout; } if (hostptr->h_addrtype != AF_INET) { SNMPErrno = SNMPE_INET; goto SNMPConnectout; } bcopy(hostptr->h_addr, (char*)&tmpaddr, hostptr->h_length); sc->IP = tmpaddr.s_addr; } #ifdef DEBUG if (debug > 5) fprintf(stderr, "Using IP address %s\n", inet_ntoa(tmpaddr)); #endif /* debug */ /* open a UDP socket to remote bridge */ /* fill in serv_addr with the address of the remote bridge */ bzero((char*)&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = sc->IP; serv_addr.sin_port = htons(SNMP_PORT); /* open a udp socket */ if ((sc->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { SNMPErrno = SNMPE_BADSOCK; goto SNMPConnectout; } if (connect(sc->sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { SNMPErrno = SNMPE_CONNECT; goto SNMPConnectout; } #endif /* socket */ err = 0; /* good */ sc->validsocket = 1; SNMPConnectout: if (err) SNMPDisconnect(sc); /* don't leak memory */ return err; } /* SNMPConnect */ /*********************************************************************/ /* Function: SNMPInit /* /* Description: /* Initialize SNMP module. /* /* Returns: 0 for good /* !0 for bad /* /* if bad, will set SNMPErrno /*********************************************************************/ int SNMPInit() { } /* SNMPInit */ /*********************************************************************/ /* Function: SNMPDisconnect /* /* Description: /* Disconnect from a snmp host connected to with SNMPConnect /* /* Returns: 0 for good /* !0 for bad /* /* if bad, will set SNMPErrno /*********************************************************************/ int SNMPDisconnect(sc) struct SNMPConnection *sc; { extern int debug; #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: Closing wattcp socket\n"); #endif /* DEBUG */ #ifdef WATTCP if (sc->validsocket) { sock_close(sc->s); sc->validsocket = 0; } #endif /* WATTCP */ #ifdef SOCKET if (sc->validsocket) { close (sc->sockfd); sc->validsocket = 0; } #endif /* SOCKET */ #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: freeing sc->buffer\n"); #endif /* DEBUG */ if (sc->buffer) { free(sc->buffer); sc->buffer = NULL; } #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: freeing sc->req\n"); #endif /* DEBUG */ if (sc->req) { free(sc->req); sc->req = NULL; } #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: freeing sc->reqr\n"); #endif /* DEBUG */ if (sc->reqr) { free(sc->reqr); sc->reqr = NULL; } #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: freeing sc->hostname\n"); #endif /* DEBUG */ if (sc->hostname) { free(sc->hostname); sc->hostname = NULL; } #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: freeing sc->community\n"); #endif /* DEBUG */ if (sc->community) { free(sc->community); sc->community = NULL; } #ifdef NETSTAT NetStatus(NETSTAT_CLOSING); #endif /* NETSTAT */ #ifdef WATTCP if (sc->s) { free(sc->s); sc->s = NULL; } #endif /* WATTCP */ #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ #ifdef DEBUG if (debug > 1) fprintf(stderr, "SNMPDisconnect: returning\n"); #endif /* DEBUG */ return 0; /* always */ } /* SNMPDisconnect */ /*********************************************************************/ /* Function: SendUDP /* /* Description: /* Make initial connection to remote snmp host. /* /* Returns: 0 for good /* !0 for bad /* /* if bad, will set SNMPErrno /*********************************************************************/ int SendUDP(sc, sendb,sendl) struct SNMPConnection *sc; char *sendb; short sendl; { extern int SNMPErrno; #ifdef NETSTAT NetStatus(NETSTAT_TRANSMITTING); #endif /* NETSTAT */ #ifdef WATTCP sock_write(sc->s, (byte *) sendb, sendl ); #endif /* WATTCP */ #ifdef SOCKET if (write(sc->sockfd, (char *)sendb, (int)sendl) != sendl) { #ifdef DEBUG perror ("write()"); #endif /* DEBUG */ SNMPErrno = SNMPE_WRITE; return 1; } #endif /* SOCKET */ #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ return 0; } /*********************************************************************/ /* Function: ReceiveUDP /* /* Description: /* Make initial connection to remote snmp host. /* /* Returns: 0 for good /* !0 for bad /* /* if bad, will set SNMPErrno /*********************************************************************/ int ReceiveUDP(sc, rcvb, rcvl) struct SNMPConnection *sc; char *rcvb; int *rcvl; { extern int SNMPErrno; int err = 1; /* bad */ #ifdef WATTCP int len; /* receive length */ int status = 0; /* receive status */ long tot_timeout; /* time out */ /* set time out */ tot_timeout = set_timeout((short)SNMP_READ_TIMEOUT); #ifdef NETSTAT NetStatus(NETSTAT_WAITING); #endif /* NETSTAT */ /* loop until receives a packet or timeout */ while (1) { sock_tick(sc->s, &status ); if ((chk_timeout(tot_timeout)) && (tot_timeout)) { SNMPErrno = SNMPE_TIMEOUT; /* fprintf(stdout, ""); */ #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ goto ReceiveUDPout; } if (sock_dataready(sc->s)) { #ifdef NETSTAT NetStatus(NETSTAT_NONE); NetStatus(NETSTAT_READING); #endif /* NETSTAT */ len = sock_fastread(sc->s, (byte *)rcvb, *rcvl); *rcvl = len; err = 0; /* good */ #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ goto ReceiveUDPout; } } sock_err: if (status == 1) SNMPErrno = SNMPE_READ; if (status == 2) { SNMPErrno = SNMPE_TIMEOUT; /*fprintf(stdout, ""); */ } ReceiveUDPout: #ifdef NETSTAT NetStatus(NETSTAT_NONE); #endif /* NETSTAT */ return err; #endif /* WATTCP */ #ifdef SOCKET fd_set rfd; struct timeval timout; int n; FD_ZERO (&rfd); FD_SET (sc->sockfd, &rfd); timout.tv_usec = 0; timout.tv_sec = SNMP_READ_TIMEOUT; if (select (sc->sockfd+1, &rfd, (fd_set *)0, (fd_set *)0, &timout) < 0) { #ifdef DEBUG fprintf(stderr, "select error in ReceiveUDP()\n"); #endif SNMPErrno = SNMPE_READ; goto ReceiveUDPout; } if (!FD_ISSET(sc->sockfd, &rfd)) { /* timeout */ SNMPErrno = SNMPE_TIMEOUT; goto ReceiveUDPout; } if ((n = recv(sc->sockfd, (char*)rcvb, (int)*rcvl, 0)) < 0) { #ifdef DEBUG perror("recv: "); #endif SNMPErrno = SNMPE_READ; goto ReceiveUDPout; } *rcvl = n; err = 0; ReceiveUDPout: return err; #endif /* SOCKET */ } /*********************************************************************/ /* Function: SNMPRequest /* /* Description: /* Perform an snmp Operation. /* /* Returns: 0 for good /* !0 for bad /* /* if bad, will set SNMPErrno /*********************************************************************/ int SNMPRequestObj(sc) struct SNMPConnection *sc; { char *bp; /* temp buffer ptr */ short slen; /* send length */ int rlen; /* rcv length */ int retry; /* number of retries */ static long myid; /* SNMP request ID */ int err; extern int SNMPErrno; int x; err = 1; /* bad */ retry = 0; sendRetry: /* retry send */ /* fill in request struct */ sc->req->errorStatus = 0; sc->req->errorIndex = 0; /* make all Get requests with a type Null for an object */ /* some devices (HP in particular don't respond if this is other than null */ if ((sc->req->command == snmpGetRequest) || (sc->req->command == snmpNextRequest)) { for (x = 0; x < sc->req->reqCount; ++x) { sc->req->list[x].objType = PC_Null; #ifdef SNMP_XDEBUG fprintf(stderr, "sc->req->list[x].objType=%d\n", (int)sc->req->list[x].objType); #endif /* SNMP_XDEBUG */ } } sc->req->id = ++myid; bp = sc->buffer; slen = SNMP_PKT_MAX; /* encode SNMP request. bp points to SNMP packet */ if ((snmpEncodePkt(sc->req, (u_char **) &bp, &slen))!= snmpErrorNone) { SNMPErrno = SNMPE_ENCODE; goto SNMPRequestout; } if (SendUDP(sc, bp, slen)) { /* leave SNMPErrno from above */ goto SNMPRequestout; } recvRetry: /* retry receive */ /* receive packet in buffer of length SNMP_PKT_MAX */ rlen = SNMP_PKT_MAX; if (ReceiveUDP(sc, sc->buffer, &rlen)) { if ((SNMPErrno == SNMPE_TIMEOUT) && (retry++ < 8)) /* retry */ goto sendRetry; else goto SNMPRequestout; } /* ReceiveUDP */ /* decode the packet */ if (snmpDecodePkt(sc->reqr, (u_char *) sc->buffer, rlen)) { SNMPErrno = SNMPE_DECODE; goto SNMPRequestout; } /* if id doesn't match then discard and wait for next pkt. */ if (sc->reqr->id != myid) goto recvRetry; /* if snmp error no such name */ if (sc->reqr->errorStatus == snmpErrorNoSuchName) { SNMPErrno = SNMPE_NOSUCHNAME; goto SNMPRequestout; } /* if snmp error bad value */ if (sc->reqr->errorStatus == snmpErrorBadValue) { SNMPErrno = SNMPE_BADVALUE; goto SNMPRequestout; } /* if snmp error generic */ if (sc->reqr->errorStatus == snmpErrorGeneric) { SNMPErrno = SNMPE_GENERIC; goto SNMPRequestout; } err = 0; /* no error */ SNMPRequestout: return err; } /* SNMPRequest */