ftp.nice.ch/pub/next/unix/network/system/gated.2.1pl2.NI.bs.tar.gz#/gated-2.1/src/snmp.c

This is snmp.c in view mode; [Download] [Up]

/*
 *  $Header: /disk/d/src/devel/gated/dist/src/RCS/snmp.c,v 2.1 92/02/24 14:13:02 jch Exp $
 */

/*%Copyright%*/
/************************************************************************
*									*
*	GateD, Release 2						*
*									*
*	Copyright (c) 1990,1991,1992 by Cornell University		*
*	    All rights reserved.					*
*									*
*	THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY		*
*	EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT		*
*	LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY		*
*	AND FITNESS FOR A PARTICULAR PURPOSE.				*
*									*
*	Royalty-free licenses to redistribute GateD Release		*
*	2 in whole or in part may be obtained by writing to:		*
*									*
*	    GateDaemon Project						*
*	    Information Technologies/Network Resources			*
*	    143 Caldwell Hall						*
*	    Cornell University						*
*	    Ithaca, NY 14853-2602					*
*									*
*	GateD is based on Kirton's EGP, UC Berkeley's routing		*
*	daemon	 (routed), and DCN's HELLO routing Protocol.		*
*	Development of Release 2 has been supported by the		*
*	National Science Foundation.					*
*									*
*	Please forward bug fixes, enhancements and questions to the	*
*	gated mailing list: gated-people@gated.cornell.edu.		*
*									*
*	Authors:							*
*									*
*		Jeffrey C Honig <jch@gated.cornell.edu>			*
*		Scott W Brim <swb@gated.cornell.edu>			*
*									*
*************************************************************************
*									*
*      Portions of this software may fall under the following		*
*      copyrights:							*
*									*
*	Copyright (c) 1988 Regents of the University of California.	*
*	All rights reserved.						*
*									*
*	Redistribution and use in source and binary forms are		*
*	permitted provided that the above copyright notice and		*
*	this paragraph are duplicated in all such forms and that	*
*	any documentation, advertising materials, and other		*
*	materials related to such distribution and use			*
*	acknowledge that the software was developed by the		*
*	University of California, Berkeley.  The name of the		*
*	University may not be used to endorse or promote		*
*	products derived from this software without specific		*
*	prior written permission.  THIS SOFTWARE IS PROVIDED		*
*	``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,	*
*	INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF	*
*	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.		*
*									*
************************************************************************/


#if	defined(AGENT_SNMP)
#include "include.h"
#include "snmp.h"
#include <snmp.h>
#include "egp.h"

static int snmp_request_next;		/* Look at lexically next object */
static int snmp_request_object;		/* Return object identifier also */
static int snmp_request_set;		/* Request is to set variable */

bits snmp_types[] =
{
    {AGENT_REG, "Register"},
    {AGENT_REQ, "Request"},
    {AGENT_ERR, "Error"},
    {AGENT_RSP, "Response"},
    {AGENT_REQN, "RequestNextObject"},
    {AGENT_REQO, "RequestObject"},
    {AGENT_RSPO, "ResponseObject"},
    {AGENT_TRAP, "TrapRequest"},
    {AGENT_SET, "SetRequest"},
    {AGENT_QUERY, "Query"},
    {AGENT_REGSET, "RegisterSet"},
    {0, 0}
};

bits snmp_errors[] =
{
    {NOERR, "noError"},
    {TOOBIG, "tooBig"},
    {NOSUCH, "noSuchName"},
    {BADVAL, "badValue"},
    {RDONLY, "readOnly",},
    {GENERRS, "genErr",},
    {0, 0}
};


int doing_snmp = TRUE;
static task *snmp_task = (task *) 0;

static int ipRoute();

#define	ipRoutePrefix	1, 3, 6, 1, 2, 1, 4, 21, 1
#define	ipRouteDest	1
#define	ipRouteIfIndex	2
#define	ipRouteMetric1	3
#define	ipRouteMetric2	4
#define	ipRouteMetric3	5
#define	ipRouteMetric4	6
#define	ipRouteNextHop	7
#define	ipRouteType	8
#define	ipRouteProto	9
#define	ipRouteAge	10
#define	ipRouteMask	11
#define	ipRouteMetric5	12
#define	ipRouteInfo	13

#ifdef	PROTO_EGP
static int egp();

#define	egpPrefix	1, 3, 6, 1, 2, 1, 8
#define	egpInMsgs	1
#define	egpInErrors	2
#define	egpOutMsgs	3
#define	egpOutErrors	4
#define	egpAs		6

static int egpNeigh();

#define	egpNeighPrefix	5, 1
#define	egpNeighState		1
#define egpNeighAddr		2
#define egpNeighAs		3
#define egpNeighInMsgs		4
#define egpNeighInErrs		5
#define egpNeighOutMsgs		6
#define egpNeighOutErrs		7
#define egpNeighInErrMsgs	8
#define egpNeighOutErrMsgs	9
#define egpNeighStateUps	10
#define egpNeighStateDowns	11
#define egpNeighIntervalHello	12
#define egpNeighIntervalPoll	13
#define egpNeighMode		14
#define egpNeighEventTrigger	15
#endif				/* PROTO_EGP */

static struct mibtbl snmptbl[] =
{
    0,
    {ipRoutePrefix, ipRouteDest}, 0, ipRoute, "ipRouteDest",
    0,
    {ipRoutePrefix, ipRouteIfIndex}, 0, ipRoute, "ipRouteIfIndex",
    0,
    {ipRoutePrefix, ipRouteMetric1}, 0, ipRoute, "ipRouteMetric1",
    0,
    {ipRoutePrefix, ipRouteMetric2}, 0, ipRoute, "ipRouteMetric2",
    0,
    {ipRoutePrefix, ipRouteMetric3}, 0, ipRoute, "ipRouteMetric3",
    0,
    {ipRoutePrefix, ipRouteMetric4}, 0, ipRoute, "ipRouteMetric4",
    0,
    {ipRoutePrefix, ipRouteNextHop}, 0, ipRoute, "ipRouteNextHop",
    0,
    {ipRoutePrefix, ipRouteType}, 0, ipRoute, "ipRouteType",
    0,
    {ipRoutePrefix, ipRouteProto}, 0, ipRoute, "ipRouteProto",
    0,
    {ipRoutePrefix, ipRouteAge}, 0, ipRoute, "ipRouteAge",
    0,
    {ipRoutePrefix, ipRouteMask}, 0, ipRoute, "ipRouteMask",
    0,
    {ipRoutePrefix, ipRouteMetric5}, 0, ipRoute, "ipRouteMetric5",
#ifdef	PROTO_EGP
    0,
    {egpPrefix, egpInMsgs}, MIBF_ONLY, egp, "egpInMsgs",
    0,
    {egpPrefix, egpInErrors}, MIBF_ONLY, egp, "egpInErrors",
    0,
    {egpPrefix, egpOutMsgs}, MIBF_ONLY, egp, "egpOutMsgs",
    0,
    {egpPrefix, egpOutErrors}, MIBF_ONLY, egp, "egpOutErrors",
    0,
{egpPrefix, egpNeighPrefix, egpNeighState}, 0, egpNeigh, "egpNeighState",
    0,
  {egpPrefix, egpNeighPrefix, egpNeighAddr}, 0, egpNeigh, "egpNeighAddr",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighAs}, 0, egpNeigh, "egpNeighAs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighInMsgs}, 0, egpNeigh, "egpNeighInMsgs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighInErrs}, 0, egpNeigh, "egpNeighInErrs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighOutMsgs}, 0, egpNeigh, "egpNeighOutMsgs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighOutErrs}, 0, egpNeigh, "egpNeighOutErrs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighInErrMsgs}, 0, egpNeigh, "egpNeighInErrMsgs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighOutErrMsgs}, 0, egpNeigh, "egpNeighOutErrMsgs",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighStateUps}, 0, egpNeigh, "egpNeighStateUps",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighStateDowns}, 0, egpNeigh, "egpNeighStateDowns",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighIntervalHello}, 0, egpNeigh, "egpNeighIntervalHello",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighIntervalPoll}, 0, egpNeigh, "egpNeighIntervalPoll",
    0,
  {egpPrefix, egpNeighPrefix, egpNeighMode}, 0, egpNeigh, "egpNeighMode",
    0,
    {egpPrefix, egpNeighPrefix, egpNeighEventTrigger}, 0, egpNeigh, "egpNeighEventTrigger",
    0,
    {egpPrefix, egpAs}, MIBF_ONLY, egp, "egpAs",
#endif				/* PROTO_EGP */
    0,
    {0}, 0, 0, 0,
};

/*
 *	Trace an SNMP or SGMP packet.
 */
static void
snmp_trace(tp, direction, packet, length)
task *tp;
char *direction;
char *packet;
int length;
{
    int size, type, integer, i;
    const char *cp;
    char *pkt = packet;
    char comment[MAXHOSTNAMELENGTH];
    struct sockaddr_in addr;
    struct mibtbl *mib_ptr;

    (void) sprintf(comment, "%s %s", tp->task_name, direction);
    cp = trace_state(snmp_types, (*pkt) - 1);
    if (!cp) {
	cp = "Unknown";
    }
    tracef("%s %#A socket %d type %s(%d) length %d",
	   comment,
	   &tp->task_addr,
	   tp->task_socket,
	   cp, *pkt++, length);

    if (trace_flags & TR_UPDATE) {
	if ((pkt - packet) <= length) {
	    switch (*packet) {
		case AGENT_TRAP:
		    trace(TR_SNMP, 0, NULL);
		    type = *pkt++;
		    size = *pkt++;
		    trace(TR_SNMP, 0, "%s\ttrap type %1d",
			  comment,
			  type);
		    tracef("%s\tlength %2d variable: ",
			   comment,
			   size);
		    for (i = 0; i < size; i++) {
			tracef("%s%d", i ? "." : "", *pkt++ & 0xff);
		    }
		    trace(TR_SNMP, 0, NULL);
		    /* Fall through to display variables */
		case AGENT_RSPO:
		case AGENT_RSP:
		    if (*packet != AGENT_TRAP) {
			trace(TR_SNMP, 0, NULL);
		    }
		    while ((pkt - packet) <= length - 1) {
			switch (*pkt++) {
			    case INT:
				size = *pkt++;
				memcpy((char *) &integer, pkt, size);
				pkt += size;
				trace(TR_SNMP, 0, "%s\tinteger length %d value: %d %#x", comment, size, integer, integer);
				break;
			    case STR:
				size = *pkt++;
				tracef("%s\tstring length %d value: ", comment, size);
				for (; size; size--) {
				    tracef("%c", *pkt++);
				}
				trace(TR_SNMP, 0, NULL);
				break;
			    case IPADD:
				size = *pkt++;
				sockclear_in(&addr);
				memcpy((char *) &addr.sin_addr, pkt, size);
				pkt += size;
				trace(TR_SNMP, 0, "%s\tIP address length %d value: %A %#x",
				      comment,
				      size,
				      &addr,
				      addr.sin_addr.s_addr);
				break;
			    case CNTR:
				size = *pkt++;
				memcpy((char *) &integer, pkt, size);
				pkt += size;
				trace(TR_SNMP, 0, "%s\tcounter length %d value: %u %#x", comment, size, integer, integer);
				break;
			    case GAUGE:
				size = *pkt++;
				memcpy((char *) &integer, pkt, size);
				pkt += size;
				trace(TR_SNMP, 0, "%s\tgauge length %d value: %u %#x", comment, size, integer, integer);
				break;
			    case TIME:
				size = *pkt++;
				memcpy((char *) &integer, pkt, size);
				pkt += size;
				trace(TR_SNMP, 0, "%s\ttimer length %d value: %u %#x", comment, size, integer, integer);
				break;
			}
		    }
		    break;
		case AGENT_ERR:
		    if ((pkt - packet) < length) {
			cp = trace_state(snmp_errors, *pkt);
			if (!cp) {
			    cp = "???";
			}
			trace(TR_SNMP, 0, " error %s(%d)",
			      cp, *pkt);
		    }
		    break;
		case AGENT_REQ:
		case AGENT_REG:
		case AGENT_REQO:
		case AGENT_REQN:
		    trace(TR_SNMP, 0, NULL);
		    while ((pkt - packet) <= length - 1) {
			size = *pkt++;
			for (mib_ptr = (struct mibtbl *) tp->task_data; mib_ptr->function; mib_ptr++) {
			    if (size < mib_ptr->length) {
				continue;
			    }
			    if (!memcmp(pkt, mib_ptr->object, mib_ptr->length)) {
				tracef("%s\t%s",
				       comment,
				       mib_ptr->name);
				pkt += mib_ptr->length;
				for (i = mib_ptr->length; i < size; i++) {
				    tracef(".%d", *pkt++ & 0xff);
				}
				trace(TR_SNMP, 0, NULL);
				break;
			    }
			}
			if (!mib_ptr->function) {
			    tracef("%s\tlength %2d variable: ",
				   comment,
				   size);
			    for (i = 0; i < size; i++) {
				tracef("%s%d", i ? "." : "", *pkt++ & 0xff);
			    }
			    trace(TR_SNMP, 0, NULL);
			}
		    }
		    break;
	    }
	}
    } else {
	trace(TR_SNMP, 0, NULL);
    }
    trace(TR_SNMP, 0, NULL);
}


/*
 *  Send and trace an SNMP packet
 */
static void
snmp_send(tp, packet, size)
task *tp;
char *packet;
int size;
{
    TRACE_SNMPPKT(tp, "SEND", packet, size);

    (void) task_send_packet(tp,
			    packet,
			    size,
			    0,
			    (sockaddr_un *) 0);

    return;
}


/*
 *  Register all of our supported variables with SNMPD.
 */
/*ARGSUSED*/
static int
snmp_register(tp, p, write_only)
task *tp;
char *p;
flag_t write_only;
{
    int asize;
    struct mibtbl *mib_ptr;

    *p++ = write_only ? AGENT_REGSET : AGENT_REG;
    asize = 1;

    for (mib_ptr = (struct mibtbl *) tp->task_data; mib_ptr->function; mib_ptr++) {
	if (!write_only || (mib_ptr->flags & MIBF_WRITE)) {
	    *p++ = mib_ptr->length;
	    memcpy(p, mib_ptr->object, mib_ptr->length);
#ifdef	notdef
	    if (mib_ptr->flags & MIBF_WRITE) {
		*(p - 1)++;
		p[mib_ptr->length] = 0;
		p++;
		asize++;
	    }
#endif				/* notdef */
	    p += mib_ptr->length;
	    asize += mib_ptr->length + 1;
	}
    }

    return (asize);
}


/*
 *  Process an incoming request from SNMPD.  Speed is of the essence here.
 *  Not elegance.
 */
static void
snmp_recv(tp)
task *tp;
{
    int size;
    char agntreqpkt[SNMPMAXPKT];
    char *ptr = recv_iovec[RECV_IOVEC_DATA].iov_base;
    char *ptr1 = agntreqpkt;
    int error = 0;
    int retsize;
    int rspsize = 0, reqsize;
    struct mibtbl *mib_ptr;

    if (task_receive_packet(tp, &size)) {
	return;
    }
    TRACE_SNMPPKT(tp, "RECV", ptr, size);
    snmp_request_next = FALSE;
    snmp_request_object = FALSE;
    snmp_request_set = FALSE;
    switch (*ptr) {
	case AGENT_REG:
	case AGENT_RSP:
	case AGENT_ERR:
	case AGENT_RSPO:
	case AGENT_TRAP:
	    trace(TR_ALL, LOG_ERR, "snmp_recv: unexpected AGENT packet type");
	    return;
	case AGENT_REQN:
	    snmp_request_next = TRUE;
	case AGENT_REQO:
	    snmp_request_object = TRUE;
	case AGENT_SET:
	    if (*ptr == AGENT_SET) {
		snmp_request_set = TRUE;
	    }
	case AGENT_REQ:
	    if (snmp_request_object) {
		*ptr1++ = AGENT_RSPO;
		/* Setup space for returned object identifier */
		ASN_SET_TYPE(ptr1, IPADD);
		ASN_SET_LENGTH(ptr1, sizeof(struct in_addr));
		rspsize = ASN_LENGTH(ptr1) + 1;
		ASN_INCR(ptr1);
	    } else {
		*ptr1++ = AGENT_RSP;
		rspsize = 1;
	    }
	    ptr++;
	    reqsize = *ptr++;
	    for (mib_ptr = (struct mibtbl *) tp->task_data; mib_ptr->function; mib_ptr++) {
		if (mib_ptr->length > reqsize) {
		    continue;
		}
		if (memcmp(ptr, mib_ptr->object, mib_ptr->length) == 0) {
		    break;
		}
	    }
	    if (mib_ptr->function) {
		ptr += mib_ptr->length;
		if (!mib_ptr->function) {
		    /* No function for this variable */
		    error++;
		    retsize = NOSUCH;
		} else if (snmp_request_set && !(mib_ptr->flags & MIBF_WRITE)) {
		    /* Variable is not writable */
		    error++;
		    retsize = RDONLY;
		}
		if ((retsize = (mib_ptr->function) (mib_ptr->object[mib_ptr->length - 1],
						    ptr,
						    ptr1,
				      reqsize - mib_ptr->length)) <= 0) {
		    error++;
		    if (retsize < 0) {
			/* Error code is returned negative */
			retsize = -retsize;
		    } else {
			/* No error - assume generic */
			retsize = -GENERRS;
		    }
		} else {
		    rspsize += retsize;
		}
	    }
	    if (error) {
		agntreqpkt[0] = AGENT_ERR;
		agntreqpkt[1] = retsize;
		rspsize = 2;
	    }
	    break;
	case AGENT_QUERY:
	    rspsize = snmp_register(tp, agntreqpkt, TRUE);
	    break;
	default:
	    trace(TR_SNMP, LOG_ERR, "snmp_recv: invalid AGENT packet type");
	    agntreqpkt[0] = AGENT_ERR;
	    rspsize = 1;
	    break;
    }					/* switch */

    snmp_send(tp, agntreqpkt, rspsize);
    return;
}


/*
 *  Register all of our supported variables with SNMPD.
 */
/*ARGSUSED*/
static void
snmp_job(tip, interval)
timer *tip;
time_t interval;
{
    int size;
    char agntpkt[SNMPMAXPKT];

    size = snmp_register(tip->timer_task, agntpkt, FALSE);

    snmp_send(tip->timer_task, agntpkt, size);
}


static void
snmp_terminate(tp)
task *tp;
{
    snmp_task = (task *) 0;
    task_delete(tp);
}


static int
ipRoute(object, src, dst, size)
int object;
char *src, *dst;
int size;
{
    int integer;
    rt_entry *rt = 0;

    if (!size && snmp_request_object) {
	rt = rt_next((sockaddr_un *) 0);
    } else if (size == sizeof(struct in_addr)) {
	struct sockaddr_in dest;

	sockclear_in(&dest);
	memcpy((char *) &dest.sin_addr, src, size);

	if (snmp_request_next) {
	    rt = rt_next((sockaddr_un *) & dest);
	} else {
	    rt = rt_lookup(RTS_NETROUTE | RTS_HOSTROUTE, (sockaddr_un *) & dest);
	    if (!rt && (dest.sin_addr.s_addr == (u_long) DEFAULTNET)) {
		rt = rt_next((sockaddr_un *) & dest);
	    }
	}
    }
    if (!rt) {
	return (-NOSUCH);
    }
    if (snmp_request_object) {
	ASN_SET_VALUE((dst - sizeof(long) - 2), &rt->rt_dest.in.sin_addr);
    }
    switch (object) {
	case ipRouteDest:
	    ASN_SET_TYPE(dst, IPADD);
	    ASN_SET_LENGTH(dst, sizeof(rt->rt_dest.in.sin_addr));
	    ASN_SET_VALUE(dst, &rt->rt_dest.in.sin_addr);
	    break;

	case ipRouteIfIndex:
	    integer = rt->rt_ifp->int_index;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case ipRouteMetric1:
	    integer = rt->rt_metric;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case ipRouteMetric2:
	case ipRouteMetric3:
	case ipRouteMetric4:
	case ipRouteMetric5:
	    integer = -1;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case ipRouteNextHop:
	    ASN_SET_TYPE(dst, IPADD);
	    ASN_SET_LENGTH(dst, sizeof(rt->rt_router.in.sin_addr));
	    ASN_SET_VALUE(dst, &rt->rt_router.in.sin_addr);
	    break;

	case ipRouteType:
	    if (rt->rt_state & RTS_HOLDDOWN) {
		integer = 2;
	    } else {
		switch (rt->rt_proto) {
		    case RTPROTO_DIRECT:
			integer = 3;
			break;
		    default:
			integer = 4;
		}
	    }
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case ipRouteProto:
	    switch (rt->rt_proto) {
		case RTPROTO_RIP:
		    integer = 8;
		    break;
		case RTPROTO_HELLO:
		    integer = 7;
		    break;
		case RTPROTO_EGP:
		    integer = 5;
		    break;
		case RTPROTO_DIRECT:
		    integer = 1;
		    break;
		case RTPROTO_REDIRECT:
		    integer = 4;
		    break;
		case RTPROTO_DEFAULT:
		    integer = 2;
		    break;
		case RTPROTO_IGP:
		    integer = 9;
		    break;
		case RTPROTO_IGRP:
		    integer = 11;
		    break;
		case RTPROTO_OSPF:
		    integer = 13;
		    break;
		case RTPROTO_BGP:
		    integer = 14;
		    break;
		case RTPROTO_STATIC:
		    integer = 2;
		    break;
		default:
		    integer = 1;
	    }
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case ipRouteAge:
	    integer = rt->rt_timer;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case ipRouteMask:
	    ASN_SET_TYPE(dst, IPADD);
	    ASN_SET_LENGTH(dst, sizeof(rt->rt_dest_mask.in.sin_addr));
	    ASN_SET_VALUE(dst, &rt->rt_dest_mask.in.sin_addr);
	    break;

	default:
	    return (-NOSUCH);
    }

    return (ASN_LENGTH(dst));
}



/*ARGSUSED*/
static int
egp(object, src, dst, size)
int object;
char *src, *dst;
u_int size;
{
    u_int counter;
    int integer;

    if (size) {
	return (-NOSUCH);
    }
    if (!(doing_egp)) {
	return (-NOSUCH);
    }
    switch (object) {
	case egpInMsgs:
	    counter = egp_stats.inmsgs;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpInErrors:
	    counter = egp_stats.inerrors;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpOutMsgs:
	    counter = egp_stats.outmsgs;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpOutErrors:
	    counter = egp_stats.outerrors;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpAs:
	    integer = my_system;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	default:
	    return (-NOSUCH);
    }

    return (ASN_LENGTH(dst));
}



static int
egpNeigh(object, src, dst, size)
int object;
char *src, *dst;
int size;
{
    int neighbor = egp_neighbors;
    int integer;
    u_int counter;
    struct egpngh *ngp;

    if (!(doing_egp)) {
	return (-NOSUCH);
    }
    if (!size && snmp_request_next) {
	neighbor = 0;
    } else if (size == sizeof(struct in_addr)) {
	struct sockaddr_in dest;

	sockclear_in(&dest);
	memcpy((char *) &dest.sin_addr, src, size);

	if (dest.sin_addr.s_addr != (u_long) DEFAULTNET) {
	    for (neighbor = 0; neighbor < egp_neighbors; neighbor++) {
		if (equal(&egp_sort[neighbor]->ng_addr, &dest.sin_addr)) {
		    break;
		}
	    }
	    if (snmp_request_next) {
		neighbor++;
	    }
	} else {
	    neighbor = snmp_request_next ? 0 : egp_neighbors;
	}
    }
    if (neighbor >= egp_neighbors) {
	return (-NOSUCH);
    }
    ngp = egp_sort[neighbor];

    if (snmp_request_object) {
	ASN_SET_VALUE((dst - sizeof(ngp->ng_addr.sin_addr) - 2), &ngp->ng_addr.sin_addr);
    }
    switch (object) {
	case egpNeighState:
	    integer = ngp->ng_state + 1;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case egpNeighAddr:
	    ASN_SET_TYPE(dst, IPADD);
	    ASN_SET_LENGTH(dst, sizeof(ngp->ng_addr.sin_addr));
	    ASN_SET_VALUE(dst, &ngp->ng_addr.sin_addr);
	    break;

	case egpNeighAs:
	    integer = ngp->ng_asin;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case egpNeighInMsgs:
	    counter = ngp->ng_stats.inmsgs;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighInErrs:
	    counter = ngp->ng_stats.inerrors;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighOutMsgs:
	    counter = ngp->ng_stats.outmsgs;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighOutErrs:
	    counter = ngp->ng_stats.outerrors;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighInErrMsgs:
	    counter = ngp->ng_stats.inerrmsgs;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighOutErrMsgs:
	    counter = ngp->ng_stats.outerrmsgs;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighStateUps:
	    counter = ngp->ng_stats.stateups;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighStateDowns:
	    counter = ngp->ng_stats.statedowns;
	    ASN_SET_TYPE(dst, CNTR);
	    ASN_SET_LENGTH(dst, sizeof(counter));
	    ASN_SET_VALUE(dst, &counter);
	    break;

	case egpNeighIntervalHello:
	    integer = ngp->ng_T1;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case egpNeighIntervalPoll:
	    integer = ngp->ng_T2;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

	case egpNeighMode:
	    integer = ngp->ng_M;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

#define	egpNeighEventTriggerStart	1
#define	egpNeighEventTriggerStop	2
	case egpNeighEventTrigger:
	    if (!ngp->ng_stats.trigger) {
		ngp->ng_stats.trigger = egpNeighEventTriggerStop;
	    }
	    integer = ngp->ng_stats.trigger;
	    ASN_SET_TYPE(dst, INT);
	    ASN_SET_LENGTH(dst, sizeof(integer));
	    ASN_SET_VALUE(dst, &integer);
	    break;

    }

    return (ASN_LENGTH(dst));
}



static void
snmp_trap(trap, ptr)
int trap;
char *ptr;
{
    int i;
    struct egpngh *ngp = (struct egpngh *) ptr;
    if_entry *ifp = (if_entry *) ptr;
    static objident ifIndex =
    {10,
     {1, 3, 6, 1, 2, 1, 2, 2, 1, 1}};
    static objident egpNeighAddrObj =
    {10,
     {1, 3, 6, 1, 2, 1, 8, 5, 1, 2}};
    objident *obj_ptr;
    char *val_ptr;
    int val_size;
    int val_type;
    char trap_pkt[SNMPMAXPKT];
    int trap_size = 0;
    char *trap_ptr = trap_pkt;

    if (!snmp_task) {
	/* Return if SNMP not active */
	return;
    }
    switch (trap) {
	case LINKDOWN:
	case LINKUP:
	    obj_ptr = &ifIndex;
	    val_ptr = (char *) &ifp->int_index;
	    val_size = 1;
	    val_type = INT;
	    break;
	case EGPNHBRLOST:
	    obj_ptr = &egpNeighAddrObj;
	    val_ptr = (char *) &ngp->ng_addr;
	    val_size = sizeof(ngp->ng_addr);
	    val_type = IPADD;
	    break;
	default:
	    trace(TR_SNMP, LOG_ERR, "snmp_trap: Unknown SNMP trap type: %d", trap);
	    return;
    }

    *trap_ptr++ = AGENT_TRAP;
    ASN_SET_TYPE(trap_ptr, trap);
    ASN_SET_LENGTH(trap_ptr, obj_ptr->ncmp + val_size);
    for (i = 0; i < obj_ptr->ncmp; i++) {
	trap_ptr[i + 2] = obj_ptr->cmp[i] & 0xff;
    }
    memcpy(&trap_ptr[obj_ptr->ncmp + 2], (char *) val_ptr, val_size);
    ASN_INCR(trap_ptr);
    ASN_SET_TYPE(trap_ptr, val_type);
    ASN_SET_LENGTH(trap_ptr, val_size);
    ASN_SET_VALUE(trap_ptr, val_ptr);
    ASN_INCR(trap_ptr);
    trap_size = trap_ptr - trap_pkt;

    snmp_send(snmp_task, trap_pkt, trap_size);
    return;
}


void
snmp_trap_egpNeighborLoss(ngp)
struct egpngh *ngp;
{
    snmp_trap(EGPNHBRLOST, (char *) ngp);
}


/*ARGSUSED*/
static void
snmp_trap_ifchange(tp, ifp)
task *tp;
if_entry *ifp;
{
    snmp_trap((ifp->int_state & IFS_UP) ? LINKUP : LINKDOWN, (char *) ifp);
}


void
snmp_init()
{
    struct mibtbl *mib_ptr = snmptbl;

    if (!doing_snmp) {
	if (snmp_task) {
	    snmp_terminate(snmp_task);
	}
	return;
    } else if (snmp_task) {
	return;
    }
    
    snmp_task = task_alloc("SNMP");
    sockclear_in(&snmp_task->task_addr.in);
    snmp_task->task_addr.in.sin_port = htons(AGENT_SNMP_PORT);
    snmp_task->task_addr.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

    snmp_task->task_recv = snmp_recv;
    snmp_task->task_terminate = snmp_terminate;
    snmp_task->task_ifchange = snmp_trap_ifchange;
    snmp_task->task_data = (caddr_t) mib_ptr;

    if ((snmp_task->task_socket = task_get_socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	quit(errno);
    }
    if (!task_create(snmp_task, SNMPMAXPKT)) {
	quit(EINVAL);
    }
    if (task_set_option(snmp_task, TASKOPTION_RECVBUF, (caddr_t) (32 * 1024)) < 0) {
	quit(errno);
    }
    if (task_set_option(snmp_task, TASKOPTION_DONTROUTE, (caddr_t) TRUE) < 0) {
	quit(errno);
    }
    if (!test_flag) {
	struct sockaddr_in addr;

	sockclear_in(&addr);
	addr.sin_port = 0;
	addr.sin_addr.s_addr = htonl(INADDR_ANY);

	if (bind(snmp_task->task_socket, (struct sockaddr *) & addr, socksize(&addr)) < 0) {
	    trace(TR_ALL, LOG_ERR, "snmp_init: bind: %m");
	    quit(errno);
	}
	if (connect(snmp_task->task_socket, &snmp_task->task_addr.a, socksize(&snmp_task->task_addr.a)) < 0) {
	    trace(TR_ALL, LOG_ERR, "snmp_init: connect: %m");
	    quit(errno);
	}
    }
    (void) timer_create(snmp_task, 0, "Register", 0, (time_t) SNMP_REGISTER_INTERVAL, snmp_job);

    for (; mib_ptr->function; mib_ptr++) {
	if (!mib_ptr->length) {
	    mib_ptr->length = strlen(mib_ptr->object);
	}
    }

}


#endif				/* AGENT_SNMP */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.