1
0
Files
irix-657m-src/irix/cmd/snmp/hpagent/hpicmpsa.c++
2022-09-29 17:59:04 +03:00

304 lines
7.6 KiB
C++

/*
* Copyright 1991 Silicon Graphics, Inc. All rights reserved.
*
* System sub-agent
*
* $Revision: 1.1 $
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <sys/times.h>
#include <unistd.h>
#include <errno.h>
// #include <bstring.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/select.h>
#include "asn1.h"
#include "packet.h"
#include "subagent.h"
#include "sat.h"
#include "agent.h"
#include "hpicmpsa.h"
#include "sgisa.h"
#include "traphandler.h"
extern "C" {
#include "exception.h"
}
#define MAXPACKET (65536-60-8) /* max packet size */
const subID hpIcmpEchoReq = 1;
int get_echo_req(long addr, int datalen, int ping_timeout);
static int in_cksum(u_short *addr, int len);
static long msec(struct timeval *now, struct timeval *then);
extern sgiHWSubAgent *sgihwsa;
extern snmpTrapHandler *traph;
hpIcmpSubAgent *hpicmpsa;
hpIcmpSubAgent::hpIcmpSubAgent(void)
{
// Store address for use by other subagents
hpicmpsa = this;
// Export subtree
subtree = "1.3.6.1.4.1.11.2.7";
int rc = export("hpIcmpEcho", &subtree);
if (rc != SNMP_ERR_genErr) {
exc_errlog(LOG_ERR, 0,
"hpicmpsa: error exporting HP icmp echo request subagent");
return;
}
}
hpIcmpSubAgent::~hpIcmpSubAgent(void)
{
unexport(&subtree);
}
int
hpIcmpSubAgent::get(asnObjectIdentifier *o, asnObject **a, int *)
{
// Pull out the subID array and length
subID *subid;
unsigned int len;
oid *oi = o->getValue();
oi->getValue(&subid, &len);
// Check that the subID array is of valid size
if (len != sublen + 8 || subid[sublen + 7] != 0)
return SNMP_ERR_noSuchName;
// Switch on the subID and assign the value to *a
switch (subid[sublen]) {
case hpIcmpEchoReq: {
int echoreq = 0;
long addr;
int size, timeout;
addr = subid[len - 2];
addr = addr | (subid[len - 3] << 8);
addr = addr | (subid[len - 4] << 16);
addr = addr | (subid[len - 5] << 24);
size = subid[len - 7];
if ( size <= 0 || size > 128) {
exc_errlog(LOG_ERR, 0, "hpicmpsa: invalid packet size (%d)\n",
size);
echoreq = -4;
}
else {
timeout = subid[len - 6];
if ( timeout <= 0 ) {
exc_errlog(LOG_ERR, 0, "hpicmpsa: invalid timeout (%d)\n",
timeout);
echoreq = -4;
}
else
echoreq = get_echo_req(addr, size, timeout);
}
*a = new asnInteger((int) echoreq);
break;
}
default:
return SNMP_ERR_noSuchName;
}
return SNMP_ERR_noError;
}
int
hpIcmpSubAgent::getNext(asnObjectIdentifier *o, asnObject **a, int *t)
{
return simpleGetNext(o, a, t, hpIcmpEchoReq);
}
int
hpIcmpSubAgent::set(asnObjectIdentifier *, asnObject **, int *)
{
// No sets in this MIB group
return SNMP_ERR_noSuchName;
}
// get_echo_req just does an ICMP echo request, and returns:
// -1 if there is an internal error
// -2 if the echo request timed out
// -3 if the echo reply is not the correct reply
// -4 if the packet size is too large (or too small)
// -5 if the timeout is invalid
// time the echo request took
int
get_echo_req(long addr, int datalen, int ping_timeout)
{
union {
u_char outbuf[MAXPACKET];
struct icmp outicmp;
} outpack;
char inbuf[128];
struct icmp *icp = &outpack.outicmp;
struct protoent *proto;
struct sockaddr_in to_s, from_s;
int fromlen = sizeof(from_s);
struct timeval timeout;
struct ip *in_ip;
struct icmp *in_icmp;
// First we create a raw socket to use for the ICMP ECHO
to_s.sin_family = AF_INET;
bcopy((struct in_addr *) &addr, (caddr_t)&(to_s.sin_addr), sizeof(to_s.sin_addr));
if ((proto = getprotobyname("icmp")) == NULL) {
exc_errlog(LOG_ERR, 0,
"hpicmpsa: getprotobyname: unknown \"icmp\" protocol\n");
return -1;
}
int s = socket(AF_INET, SOCK_RAW, proto->p_proto);
if (s < 0) {
exc_errlog(LOG_ERR, 0, "hpicmpsa: %s\n",
strerror(errno));
return -1;
}
// Now we fill in a structure to use as our echo request.
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = 0;
int ident = icp->icmp_id = getpid() & 0xffff;
// Fill in timeval in the icmp packet
struct timeval last_tx;
gettimeofday(&last_tx,0);
bcopy(&last_tx, &outpack.outbuf[8], sizeof(last_tx));
icp->icmp_cksum = in_cksum((u_short *)icp, datalen + 8);
int i = sendto(s, &outpack.outbuf, datalen, 0,
&to_s, sizeof(struct sockaddr));
if ((i < 0) || (i != datalen)) {
close(s);
exc_errlog(LOG_ERR, 0, "hpicmpsa: sendto: internal error\n");
return -1;
}
timeout.tv_sec = ping_timeout;
timeout.tv_usec = 0;
fd_set fdmask;
FD_ZERO(&fdmask);
FD_SET(s, &fdmask);
for (;;) {
i = select(s+1,&fdmask,0,0,&timeout);
if (i == 0) {
exc_errlog(LOG_ERR, 0, "hpicmpsa: select: timeout\n");
return -2;
} else if (i < 0) {
close(s);
exc_errlog(LOG_ERR, 0, "hpicmpsa: select: internal error\n");
return -1;
} else {
i = recvfrom(s, inbuf, sizeof(inbuf), 0, &from_s, &fromlen);
if ( i < 0 ) {
close (s);
exc_errlog(LOG_ERR, 0,
"hpicmpsa: recvfrom: internal error\n");
return -1;
}
in_ip = (struct ip *)inbuf;
in_icmp = (struct icmp *)(inbuf + (in_ip->ip_hl << 2));
from_s.sin_addr.s_addr = ntohl(from_s.sin_addr.s_addr);
if ((in_icmp->icmp_type == ICMP_ECHOREPLY) &&
(in_icmp->icmp_id == ident) &&
(from_s.sin_addr.s_addr == to_s.sin_addr.s_addr)) {
close (s);
gettimeofday(&last_tx,0);
struct timeval tv;
bcopy(&icp->icmp_data[0], &tv, sizeof(tv));
int triptime = msec(&last_tx, &tv);
return triptime;
}
else {
close (s);
exc_errlog(LOG_ERR, 0,
"hpicmpsa: recvfrom: incorrect reply\n");
return -3;
}
}
}
}
/*
** Simple routine to calculate the checksum.
*/
static int
in_cksum(u_short *addr, int len)
{
register u_short *ptr;
register int sum;
u_short *lastptr;
sum = 0;
ptr = (u_short *)addr;
lastptr = ptr + (len/2);
for (; ptr < lastptr; ptr++) {
sum += *ptr;
if (sum & 0x10000) {
sum &= 0xffff;
sum++;
}
}
return (~sum & 0xffff);
}
// compute the difference of two timevals in msec.
static long
msec(struct timeval *now, struct timeval *then)
{
double val;
val = (now->tv_sec - then->tv_sec);
if (val < 1000000.0 && val > -1000000.0)
val *= 1000.0;
val += (now->tv_usec - then->tv_usec)/1000.0;
return val;
}