aboutsummaryrefslogtreecommitdiff
path: root/sbin/atm/ilmid/ilmid.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/atm/ilmid/ilmid.c')
-rw-r--r--sbin/atm/ilmid/ilmid.c2810
1 files changed, 2810 insertions, 0 deletions
diff --git a/sbin/atm/ilmid/ilmid.c b/sbin/atm/ilmid/ilmid.c
new file mode 100644
index 000000000000..e515a1088f99
--- /dev/null
+++ b/sbin/atm/ilmid/ilmid.c
@@ -0,0 +1,2810 @@
+/*
+ *
+ * ===================================
+ * HARP | Host ATM Research Platform
+ * ===================================
+ *
+ *
+ * This Host ATM Research Platform ("HARP") file (the "Software") is
+ * made available by Network Computing Services, Inc. ("NetworkCS")
+ * "AS IS". NetworkCS does not provide maintenance, improvements or
+ * support of any kind.
+ *
+ * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
+ * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
+ * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
+ * In no event shall NetworkCS be responsible for any damages, including
+ * but not limited to consequential damages, arising from or relating to
+ * any use of the Software or related support.
+ *
+ * Copyright 1994-1998 Network Computing Services, Inc.
+ *
+ * Copies of this Software may be made, however, the above copyright
+ * notice must be reproduced on all copies.
+ *
+ * @(#) $Id: ilmid.c,v 1.9 1998/08/13 20:15:28 jpt Exp $
+ *
+ */
+
+/*
+ * User utilities
+ * --------------
+ *
+ * Implement very minimal ILMI address registration.
+ *
+ * Implement very crude and basic support for "cracking" and
+ * "encoding" SNMP PDU's to support ILMI prefix and NSAP address
+ * registration. Code is not robust nor is it meant to provide any
+ * "real" SNMP support. Much of the code expects predetermined values
+ * and will fail if anything else is found. Much of the "encoding" is
+ * done with pre-computed PDU's.
+ *
+ * See "The Simple Book", Marshall T. Rose, particularly chapter 5,
+ * for ASN and BER information.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: ilmid.c,v 1.9 1998/08/13 20:15:28 jpt Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#if (defined(BSD) && (BSD >= 199103))
+#include <err.h>
+#endif
+
+#ifdef BSD
+#if __FreeBSD_version < 300001
+#include <stdlib.h>
+#ifdef sun
+#include <unistd.h>
+#endif /* sun */
+#else
+#include <unistd.h>
+#endif /* __FreeBSD_version >= 300001 */
+#endif /* BSD */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <netatm/port.h>
+#include <netatm/atm.h>
+#include <netatm/atm_if.h>
+#include <netatm/atm_sigmgr.h>
+#include <netatm/atm_sap.h>
+#include <netatm/atm_sys.h>
+#include <netatm/atm_ioctl.h>
+
+#include <dev/hea/eni_stats.h>
+#include <dev/hfa/fore_aali.h>
+#include <dev/hfa/fore_slave.h>
+#include <dev/hfa/fore_stats.h>
+#include <netatm/uni/unisig_var.h>
+
+#define MAX_LEN 9180
+
+#define MAX_UNITS 8
+
+/*
+ * Time to sleep between loops
+ */
+#define SLEEP_TIME 10
+/*
+ * Time to pass between sending coldStart TRAPs
+ */
+#define TRAP_TIME 5
+
+/*
+ * Define some ASN types
+ */
+#define ASN_INTEGER 0x02
+#define ASN_OCTET 0x04
+#define ASN_OBJID 0x06
+#define ASN_SEQUENCE 0x30
+#define ASN_IPADDR 0x40
+#define ASN_TIMESTAMP 0x43
+
+/*
+ * Define SNMP PDU types
+ */
+#define PDU_TYPE_GET 0xA0
+#define PDU_TYPE_GETNEXT 0xA1
+#define PDU_TYPE_GETRESP 0xA2
+#define PDU_TYPE_SET 0xA3
+#define PDU_TYPE_TRAP 0xA4
+
+/*
+ * Every SNMP PDU has the first four fields of this header. The only type
+ * which doesn't have the last three fields is the TRAP type.
+ */
+struct snmp_header {
+ int pdulen;
+ int version;
+ char community[64];
+ int pdutype;
+ int reqid;
+ int error;
+ int erridx;
+};
+typedef struct snmp_header Snmp_Header;
+
+/*
+ * Define our internal representation of an OBJECT IDENTIFIER
+ */
+struct objid {
+ int oid[128];
+};
+typedef struct objid Objid;
+
+/*
+ * Define some OBJET IDENTIFIERS that we'll try to reply to:
+ *
+ * sysUpTime: number of time ticks since this deamon came up
+ * netpfx_oid: network prefix table
+ * unitype: is this a PRIVATE or PUBLIC network link
+ * univer: which version of UNI are we running
+ * devtype: is this a USER or NODE ATM device
+ * setprefix: used when the switch wants to tell us its NSAP prefix
+ * foresiggrp: FORE specific Objid we see alot of (being connected to FORE
+ * switches...)
+ */
+Objid sysObjId = { 8, 43, 6, 1, 2, 1, 1, 2, 0 };
+Objid sysUpTime = { 8, 43, 6, 1, 2, 1, 1, 3, 0 };
+Objid foresiggrp = { 18, 43, 6, 1, 4, 1, 326, 2, 2, 2, 1, 6, 2, 1, 1, 1, 20, 0, 0 };
+Objid portidx = { 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 1, 0 };
+Objid myipnm = { 10, 43, 6, 1, 4, 1, 353, 2, 1, 2, 0 };
+Objid layeridx = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 1, 0 };
+Objid maxvcc = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 3, 0 };
+Objid unitype = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 8, 0 };
+Objid univer = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 9, 0 };
+Objid devtype = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 10, 0 };
+Objid netpfx_oid = { 9, 43, 6, 1, 4, 1, 353, 2, 7, 1 };
+Objid setprefix = { 12, 43, 6, 1, 4, 1, 353, 2, 7, 1, 1, 3, 0 };
+/*
+ * (Partialy) pre-encoded SNMP responses
+ */
+
+/*
+ * sysObjId reply
+ */
+u_char sysObjId_Resp[] = {
+ 54, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x32, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* GET Response */
+ 0x27, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* <--- request id */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x17, /* <--- len */
+ 0x82, 0x00, 0x14, /* <--- len */
+ 0x06, 0x08, /* Objid: 1.3.6.1.4.1.1.2.0 */
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00,
+ 0x06, 0x08, /* Objid: 1.3.6.1.4.1.9999.1 */
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0xce, 0x0f, 0x01
+};
+
+/*
+ * sysUpTime: reply to a sysUpTime GET request
+ */
+u_char sysUpTime_Resp[] = {
+ 45, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x29, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community - ILMI */
+ PDU_TYPE_GETRESP, /* GET Response */
+ 0x1e, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* <--- request id */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x0E, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x0A, /* <--- len */
+ /* Objid: .1.3.6.1.2.1.1.3.0 */
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00,
+ /* <--- uptime */
+};
+
+/*
+ * coldStart TRAP to start the ILMI protocol
+ */
+u_char coldStart_Trap[] = {
+ 60,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x38, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_TRAP, /* TRAP */
+ 0x2d, /* <--- len */
+ 0x06, 0x08, /* Objid: .1.3.6.1.4.1.3.1.1 */
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x03, 0x01, 0x01,
+ 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, /* IP address - 0.0.0.0 */
+ 0x02, 0x01, 0x00, /* generic trap */
+ 0x02, 0x01, 0x00, /* specific trap */
+ 0x43, 0x01, 0x00, /* Time ticks - 0 */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x10, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x0c, /* <-- len */
+ 0x06, 0x08, /* Objid: 1.3.6.1.2.1.1.3.0 */
+ 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00,
+ 0x05, 0x00 /* Null */
+};
+
+u_char GetNext_Resp[] = {
+ 49,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x2d, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */
+ 0x22, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x02, /* Error Status */
+ 0x02, 0x01, 0x01, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x12, /* <--- len */
+ 0x30, /* Seqence of */
+ 0x82, 0x00, 0x0e, /* <--- len */
+ 0x06, 0x0a, /* Objid: .1.3.6.4.1.353.2.7.1 */
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x07, 0x01,
+ 0x05, 0x00 /* Get response: NULL */
+};
+
+/*
+ * Reply to GET myIpNm
+ */
+u_char MyIpNm_Resp[] = {
+ 54,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x32, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */
+ 0x27, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x17, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x13, /* <--- len */
+ /* Objid: .1.3.6.1.4.1.353.2.1.2.1 */
+ 0x06, 0x0B, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02,
+ 0x01, 0x02, 0x01,
+ 0x40, 0x04, 0x00, 0x00, 0x00, 0x00 /* IP address */
+};
+
+/*
+ * Reply to GET portIndex - we're always 1 + unit number
+ */
+u_char PortIndex_Resp[] = {
+ 53,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x31, /* <-- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP,
+ 0x26, /* <-- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x16, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x12, /* <--- len */
+ /* Objid: .1.3.6.1.4.1.353.2.1.1.1.1.x */
+ 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x00,
+ 0x02, 0x01, 0x00, /* Value */
+};
+
+/*
+ * Reply to GET MaxVcc
+ */
+u_char maxVCC_Resp[] = {
+ 52, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x30, /* <--- len */
+ 0x02, 0x01, 0x01, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* GET Response */
+ 0x25, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* <--- request id */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x16, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x13, /* <--- len */
+ 0x06, 0x0d, /* Objid: 1.3.6.1.4.1.353.2.2.1.1.3.0 */
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02,
+ 0x02, 0x01, 0x01, 0x03, 0x00,
+ 0x02, 0x02, 0x04, 0x00 /* Value = 1024 */
+};
+
+/*
+ * Reply to GET uniType - we only support PRIVATE
+ */
+u_char UniType_Resp[] = {
+ 53,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x31, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */
+ 0x26, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x16, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x12, /* <--- len */
+ /* Objid: .1.3.6.1.4.1.353.2.2.1.1.8.0 */
+ 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x02,
+ 0x01, 0x01, 0x08, 0x00,
+ 0x02, 0x01, 0x02 /* Get response: Integer */
+ /* = UNITYPE_PRIVATE (2) */
+};
+
+#define UNIVER_UNI30 2
+#define UNIVER_UNI31 3
+#define UNIVER_UNI40 4
+
+/*
+ * Reply to GET uniVer
+ */
+u_char UniVer_Resp[] = {
+ 53,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x31, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */
+ 0x26, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x16, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x12, /* <--- len */
+ /* Objid: .1.3.6.1.4.1.353.2.2.1.1.9.0 */
+ 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x02,
+ 0x01, 0x01, 0x09, 0x00,
+ 0x02, 0x01, 0x02 /* Get response: Integer */
+ /* = UNIVER_UNI30 (2) */
+};
+
+/*
+ * Reply to GET devType - we're a host therefore we're type USER
+ */
+u_char DevType_Resp[] = {
+ 53,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x31, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version -1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */
+ 0x26, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x00, /* Error Status */
+ 0x02, 0x01, 0x00, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x16, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x12, /* <--- len */
+ /* Objid: .1.3.6.1.4.1.353.2.2.1.1.10.0 */
+ 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x02,
+ 0x01, 0x01, 0x0a, 0x00,
+ 0x02, 0x01, 0x01 /* Get response: Integer */
+ /* = DEVTYPE_USER (1) */
+};
+
+/*
+ * Reply to GET foreSigGroup.* with noSuchError
+ */
+u_char NoSuchFore_Resp[] = {
+ 85,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x51, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */
+ 0x46, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x02, /* Error Status: noSuch (2) */
+ 0x02, 0x01, 0x01, /* Error Index */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x36, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x17, /* <--- len */
+ /* Objid: .1.3.6.1.5.1.326.2.2.2.1.6.2.1.1.1.20.0.0 */
+ 0x06, 0x13,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x46,
+ 0x02, 0x02, 0x02, 0x01, 0x06, 0x02, 0x01, 0x01,
+ 0x01, 0x14, 0x00, 0x00,
+ 0x05, 0x00, /* NULL */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x17, /* <--- len */
+ /* Objid: .1.3.6.1.5.1.326.2.2.2.1.6.2.1.1.1.21.0.0 */
+ 0x06, 0x13,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x46,
+ 0x02, 0x02, 0x02, 0x01, 0x06, 0x02, 0x01, 0x01,
+ 0x01, 0x15, 0x00, 0x00,
+ 0x05, 0x00 /* NULL */
+};
+
+u_char NetPrefix_Resp[] = {
+ 50,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x00, /* <--- len */
+ 0x02, 0x01, 0x00, /* (Version - 1) */
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */
+ PDU_TYPE_SET, /* PDU_TYPE_SET */
+ 0x00, /* <--- len */
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */
+ 0x02, 0x01, 0x00,
+ 0x02, 0x01, 0x00,
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x00, /* <--- len */
+ 0x30, /* Sequence of */
+ 0x82, 0x00, 0x00, /* <--- len */
+ /* Objid: .1.3.6.1.4.1.353.2.6.1.1.3.0. */
+ 0x06, 0x00,
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02,
+ 0x06, 0x01, 0x01, 0x03, 0x00
+ /* Remainder of Objid plus SET value INTEGER =1 */
+};
+
+/*
+ * Our (incrementing) Request ID
+ */
+int Req_ID = 0;
+
+/*
+ * Temporary buffer for building response packets. Should help ensure
+ * that we aren't accidently overwriting some other memory.
+ */
+u_char Resp_Buf[1024];
+
+/*
+ * Copy the reponse into a buffer we can modify without
+ * changing the original...
+ */
+#define COPY_RESP(resp) \
+ UM_COPY ( (resp), Resp_Buf, (resp)[0] + 1 )
+
+/*
+ * TRAP generic trap types
+ */
+char *Traps[] = { "coldStart", "warmStart", "linkDown", "linkUp",
+ "authenticationFailure", "egpNeighborLoss",
+ "enterpriseSpecific" };
+
+
+int NUnits;
+/*
+ * Time last coldStart trap was sent to this unit
+ */
+time_t last_trap[MAX_UNITS];
+/*
+ * fd for units still awiting coldStart TRAP from network side
+ */
+int trap_fd[MAX_UNITS];
+/*
+ * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests
+ */
+int ilmi_fd[MAX_UNITS];
+/*
+ * Local copy for HARP physical configuration information
+ */
+struct air_cfg_rsp Cfg[MAX_UNITS + 1];
+/*
+ * Local copy for HARP interface configuration information
+ */
+struct air_int_rsp Intf[MAX_UNITS + 1];
+
+/*
+ * When this daemon started
+ */
+struct timeval starttime;
+
+int Debug_Level = 0;
+
+char *progname;
+char hostname[80];
+
+ /* File to write debug messages to */
+#define LOG_FILE "/var/log/ilmid"
+FILE *Log; /* File descriptor for log messages */
+
+extern int errno;
+
+#ifdef sun
+extern char *optarg;
+extern int optind, opterr;
+extern int getopt __P((int, char **, char *));
+#endif /* sun */
+
+void set_reqid __P ( ( u_char *, int ) );
+void Increment_DL __P ( ( int ) );
+void Decrement_DL __P ( ( int ) );
+
+static char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+/*
+ * Write a syslog() style timestamp
+ *
+ * Write a syslog() style timestamp with month, day, time and hostname
+ * to the log file.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+write_timestamp()
+{
+ time_t clock;
+ struct tm *tm;
+
+ clock = time ( (time_t)NULL );
+ tm = localtime ( &clock );
+
+ if ( Log )
+ fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
+ Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec, hostname );
+
+ return;
+
+}
+
+/*
+ * Utility to pretty print buffer as hex dumps
+ *
+ * Arguments:
+ * bp - buffer pointer
+ * len - length to pretty print
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+hexdump ( bp, len )
+ u_char *bp;
+ int len;
+{
+ int i, j;
+
+ /*
+ * Print as 4 groups of four bytes. Each byte seperated
+ * by space, each block of four seperated, and two blocks`
+ * of eight also seperated.
+ */
+ for ( i = 0; i < len; i += 16 ) {
+ if ( Log )
+ write_timestamp();
+ for ( j = 0; j < 4 && j + i < len; j++ )
+ if ( Log )
+ fprintf ( Log, "%.2x ", *bp++ );
+ if ( Log )
+ fprintf ( Log, " " );
+ for ( ; j < 8 && j + i < len; j++ )
+ if ( Log )
+ fprintf ( Log, "%.2x ", *bp++ );
+ if ( Log )
+ fprintf ( Log, " " );
+ for ( ; j < 12 && j + i < len; j++ )
+ if ( Log )
+ fprintf ( Log, "%.2x ", *bp++ );
+ if ( Log )
+ fprintf ( Log, " " );
+ for ( ; j < 16 && j + i < len; j++ )
+ if ( Log )
+ fprintf ( Log, "%.2x ", *bp++ );
+ if ( Log )
+ fprintf ( Log, "\n" );
+ }
+
+ return;
+
+}
+
+/*
+ * Get lengths from PDU encodings
+ *
+ * Lengths are sometimes encoded as a single byte if the length
+ * is less the 127 but are more commonly encoded as one byte with
+ * the high bit set and the lower seven bits indicating the nuber
+ * of bytes which make up the length value. Trailing data is (to my
+ * knowledge) not 7-bit encoded.
+ *
+ * Arguments:
+ * bufp - pointer to buffer pointer
+ *
+ * Returns:
+ * bufp - updated buffer pointer
+ * <len> - decoded length
+ *
+ */
+int
+asn_get_pdu_len ( bufp )
+ u_char **bufp;
+{
+ u_char *bp = *bufp;
+ int len = 0;
+ int i, b;
+
+ b = *bp++;
+ if ( b & 0x80 ) {
+ for ( i = 0; i < (b & ~0x80); i++ )
+ len = len * 256 + *bp++;
+ } else
+ len = b;
+
+ *bufp = bp;
+ return ( len );
+}
+
+/*
+ * Get an 7-bit encoded value.
+ *
+ * Get a value which is represented using a 7-bit encoding. The last
+ * byte in the stream has the high-bit clear.
+ *
+ * Arguments:
+ * bufp - pointer to the buffer pointer
+ * len - pointer to the buffer length
+ *
+ * Returns:
+ * bufp - updated buffer pointer
+ * len - updated buffer length
+ * <val> - value encoding represented
+ *
+ */
+int
+asn_get_encoded ( bufp, len )
+ u_char **bufp;
+ int *len;
+{
+ u_char *bp = *bufp;
+ int val = 0;
+ int l = *len;
+
+ /*
+ * Keep going while high bit is set
+ */
+ do {
+ /*
+ * Each byte can represent 7 bits
+ */
+ val = ( val << 7 ) + ( *bp & ~0x80 );
+ l--;
+ } while ( *bp++ & 0x80 );
+
+ *bufp = bp; /* update buffer pointer */
+ *len = l; /* update buffer length */
+
+ return ( val );
+}
+
+/*
+ * Get a BER encoded integer
+ *
+ * Intergers are encoded as one byte length followed by <length> data bytes
+ *
+ * Arguments:
+ * bufp - pointer to the buffer pointer
+ *
+ * Returns:
+ * bufp - updated buffer pointer
+ * <val> - value of encoded integer
+ *
+ */
+int
+asn_get_int ( bufp )
+ u_char **bufp;
+{
+ int i;
+ int len;
+ int v = 0;
+ u_char *bp = *bufp;
+
+ len = *bp++;
+ for ( i = 0; i < len; i++ ) {
+ v = (v * 256) + *bp++;
+ }
+ *bufp = bp;
+ return ( v );
+}
+
+/*
+ * Utility to print a object identifier
+ *
+ * Arguments:
+ * objid - pointer to objid representation
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+print_objid ( objid )
+ Objid *objid;
+{
+ int i;
+
+ /*
+ * First oid coded as 40 * X + Y
+ */
+ if ( Log ) {
+ write_timestamp();
+ fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
+ objid->oid[1] % 40 );
+ }
+ for ( i = 2; i <= objid->oid[0]; i++ )
+ if ( Log )
+ fprintf ( Log, ".%d", objid->oid[i] );
+ if ( Log )
+ fprintf ( Log, "\n" );
+
+ return;
+}
+
+/*
+ * Get Object Identifier
+ *
+ * Arguments:
+ * bufp - pointer to buffer pointer
+ * objid - pointer to objid buffer
+ *
+ * Returns:
+ * bufp - updated buffer pointer
+ * objid - internal representation of encoded objid
+ *
+ */
+void
+asn_get_objid ( bufp, objid )
+ u_char **bufp;
+ Objid *objid;
+{
+ int len;
+ u_char *bp = *bufp;
+ int *ip = (int *)objid + 1; /* First byte will contain length */
+ int oidlen = 0;
+
+ len = *bp++;
+ while ( len ) {
+ *ip++ = asn_get_encoded ( &bp, &len );
+ oidlen++;
+ }
+ objid->oid[0] = oidlen;
+ *bufp = bp;
+
+ if ( Debug_Level > 1 )
+ print_objid ( objid );
+
+ return;
+}
+
+/*
+ * Get OCTET STRING
+ *
+ * Octet strings are encoded as a 7-bit encoded length followed by <len>
+ * data bytes;
+ *
+ * Arguments:
+ * bufp - pointer to buffer pointer
+ * octet - pointer to octet buffer
+ *
+ * Returns:
+ * bufp - updated buffer pointer
+ * octet - encoded Octet String
+ *
+ */
+void
+asn_get_octet ( bufp, octet )
+ u_char **bufp;
+ char *octet;
+{
+ u_char *bp = *bufp;
+ int i = 0;
+ int len = 0;
+
+ /*
+ * &i is really a dummy value here as we don't keep track
+ * of the ongoing buffer length
+ */
+ len = asn_get_encoded ( &bp, &i );
+
+ for ( i = 0; i < len; i++ )
+ *octet++ = *bp++;
+
+ *bufp = bp;
+
+ return;
+
+}
+
+/*
+ * Utility to print SNMP PDU header information
+ *
+ * Arguments:
+ * Hdr - pointer to internal SNMP header structure
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+print_header ( Hdr )
+ Snmp_Header *Hdr;
+{
+ if ( Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x\n",
+ Hdr->pdulen, Hdr->version + 1, Hdr->community,
+ Hdr->pdutype );
+ }
+ if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
+ fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
+ Hdr->reqid, Hdr->error, Hdr->erridx );
+
+ return;
+
+}
+
+/*
+ * Crack the SNMP header
+ *
+ * Pull the PDU length, SNMP version, SNMP community and PDU type.
+ * If present, also pull out the Request ID, Error status, and Error
+ * index values.
+ *
+ * Arguments:
+ * bufp - pointer to buffer pointer
+ *
+ * Returns:
+ * bufp - updated buffer pointer
+ * - generated SNMP header
+ *
+ */
+Snmp_Header *
+asn_get_header ( bufp )
+ u_char **bufp;
+{
+ Snmp_Header *h;
+ u_char *bp = *bufp;
+
+ /*
+ * Allocate memory to hold the SNMP header
+ */
+ if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
+ return ( (Snmp_Header *)NULL );
+
+ /*
+ * PDU has to start as SEQUENCE OF
+ */
+ if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
+ return ( (Snmp_Header *)NULL );
+
+ /*
+ * Get the length of remaining PDU data
+ */
+ h->pdulen = asn_get_pdu_len ( &bp );
+
+ /*
+ * We expect to find an integer encoding Version-1
+ */
+ if ( *bp++ != ASN_INTEGER ) {
+ return ( (Snmp_Header *)NULL );
+ }
+ h->version = asn_get_int ( &bp );
+
+ /*
+ * After the version, we need the community name
+ */
+ if ( *bp++ != ASN_OCTET ) {
+ return ( (Snmp_Header *)NULL );
+ }
+ UM_ZERO ( h->community, sizeof ( h->community ) );
+ asn_get_octet ( &bp, h->community );
+
+ /*
+ * Single byte PDU type
+ */
+ h->pdutype = *bp++;
+
+ /*
+ * If this isn't a TRAP PDU, then look for the rest of the header
+ */
+ if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
+
+ bp++; /* Skip over data len */
+
+ /* Request ID */
+ if ( *bp++ != ASN_INTEGER ) {
+ return ( (Snmp_Header *)NULL );
+ }
+ h->reqid = asn_get_int ( &bp );
+
+ /* Error Status */
+ if ( *bp++ != ASN_INTEGER ) {
+ return ( (Snmp_Header *)NULL );
+ }
+ h->error = asn_get_int ( &bp );
+
+ /* Error Index */
+ if ( *bp++ != ASN_INTEGER ) {
+ return ( (Snmp_Header *)NULL );
+ }
+ h->erridx = asn_get_int ( &bp );
+
+ }
+
+ *bufp = bp;
+
+ if ( Debug_Level > 2 )
+ print_header ( h );
+
+ return ( h );
+
+}
+
+/*
+ * Compare to internal OID representations
+ *
+ * Arguments:
+ * oid1 - Internal Object Identifier
+ * oid2 - Internal Object Identifier
+ *
+ * Returns:
+ * 0 - Objid's match
+ * 1 - Objid's don't match
+ *
+ */
+int
+oid_cmp ( oid1, oid2 )
+ Objid *oid1, *oid2;
+{
+ int i;
+
+ /*
+ * Compare lengths
+ */
+ if ( !(oid1->oid[0] == oid2->oid[0]) )
+ /* Different lengths */
+ return ( 1 );
+
+ /*
+ * value by value compare
+ */
+ for ( i = 1; i <= oid1->oid[0]; i++ ) {
+ if ( !(oid1->oid[i] == oid2->oid[i]) )
+ /* values don't match */
+ return ( 1 );
+ }
+
+ /* Objid's are identical */
+ return ( 0 );
+}
+
+/*
+ * Encode a timeval as the number of time ticks
+ *
+ * Time ticks are the number of 100th's of a second since some event.
+ * For sysUpTime, this is the time ticks since the application started,
+ * not since the host came up. We only support encoding ticks since we
+ * started running (what we are calling 'starttime').
+ *
+ * Arguments:
+ * bufp - pointer to buffer pointer
+ *
+ * Returns:
+ * bufp - updated buffper pointer
+ * len - number of bytes to encode time ticks value
+ * - ticks since 'starttime' encoded in buffer
+ *
+ */
+int
+asn_encode_ticks ( bufp, ret )
+ u_char **bufp;
+ int *ret;
+{
+ struct timeval timenow;
+ struct timeval timediff;
+ u_char *bp = *bufp;
+ int len, ticks;
+
+ (void) gettimeofday ( &timenow, NULL );
+ /*
+ * Adjust for subtraction
+ */
+ timenow.tv_sec--;
+ timenow.tv_usec += 1000000;
+
+ /*
+ * Compute time since 'starttime'
+ */
+ timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
+ timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
+
+ /*
+ * Adjust difference timeval
+ */
+ if ( timediff.tv_usec > 1000000 ) {
+ timediff.tv_usec -= 1000000;
+ timediff.tv_sec++;
+ }
+
+ /*
+ * Compute 100th's of second in diff time structure
+ */
+ *ret = ticks = (timediff.tv_sec * 100) + (timediff.tv_usec / 10000);
+
+ /*
+ * The rest of this is just plain gross. I'm sure there
+ * are better ways to do this...
+ */
+
+ /* Compute time ticks length */
+ if ( ticks < 0xFF )
+ len = 1;
+ else if ( ticks < 0xFFFF )
+ len = 2;
+ else if ( ticks < 0xFFFFFF )
+ len = 3;
+ else
+ len = 4;
+
+ /*
+ * Encode time ticks
+ */
+ *bp++ = ASN_TIMESTAMP; /* Time Ticks */
+ *bp++ = len; /* length of value */
+
+ /* there's always a better way but this is quick and dirty... */
+ if ( ticks > 0xFFFFFF ) {
+ *bp++ = ( ticks & 0xFF000000 ) >> 24;
+ ticks &= 0xFFFFFF;
+ }
+ if ( ticks > 0xFFFF ) {
+ *bp++ = ( ticks & 0xFF0000 ) >> 16;
+ ticks &= 0xFFFF;
+ }
+ if ( ticks > 0xFF ) {
+ *bp++ = ( ticks & 0xFF00 ) >> 8;
+ ticks &= 0xFF;
+ }
+ *bp++ = ticks;
+
+ *bufp = bp;
+ return ( len + 2 );
+}
+
+/*
+ * Send back up sysUpTime response
+ *
+ * Arguments:
+ * sd - socket descriptor to send reply on
+ * reqid - original GET request id
+ *
+ * Returns:
+ * none - response sent
+ *
+ */
+void
+send_uptime_resp ( sd, reqid )
+ int sd;
+ int reqid;
+{
+ int len;
+ short *sp;
+ u_long *ip;
+ u_char *bp;
+ short val;
+ int ticks;
+
+ COPY_RESP ( sysUpTime_Resp );
+
+ bp = (u_char *)&Resp_Buf[Resp_Buf[0]+1];
+ len = asn_encode_ticks ( &bp, &ticks );
+
+ /*
+ * Adjust overall length
+ */
+ bp = (u_char *)&Resp_Buf[0];
+ *bp += len;
+
+ /*
+ * Adjust sequence lengths - works because this is my
+ * PDU and I know all the variable lengths are fixed (ie.
+ * reqid is always 4 byte encoded).
+ */
+#ifndef sun
+ sp = (short *)&Resp_Buf[3];
+ val = ntohs ( *sp );
+ *sp = htons ( val + len );
+ Resp_Buf[15] += len;
+ sp = (u_short *)&Resp_Buf[30];
+ val = ntohs ( *sp );
+ *sp = htons ( val + len );
+ sp = (u_short *)&Resp_Buf[34];
+ val = ntohs ( *sp );
+ *sp = htons ( val + len );
+#else
+ /* Sun SPARCs have alignment requirements */
+ Resp_Buf[4] += len;
+ Resp_Buf[15] += len;
+ Resp_Buf[31] += len;
+ Resp_Buf[35] += len;
+#endif /* sun */
+
+ /*
+ * Store the original request ID in the response
+ */
+ set_reqid ( Resp_Buf, reqid );
+#ifdef notdef
+#ifndef sun
+ ip = (u_long *)&Resp_Buf[18];
+ *ip = htonl ( reqid );
+#else
+ /* Sun SPARCs have alignment requirements */
+ UM_COPY ( (caddr_t)&reqid, (caddr_t)&Resp_Buf[18], sizeof(reqid) );
+#endif /* sun */
+#endif
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\tSend sysUpTime: %d\n", ticks );
+ }
+
+ if ( Debug_Level > 4 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\n===== Sent %d bytes =====\n", Resp_Buf[0] );
+ hexdump ( (u_char *)&Resp_Buf[1], Resp_Buf[0] );
+ }
+ /*
+ * Send response
+ */
+ write ( sd, (caddr_t)&Resp_Buf[1], Resp_Buf[0] );
+
+ return;
+
+}
+
+/*
+ * Set Request ID in PDU
+ *
+ * Arguments:
+ * resp - Response PDU buffer
+ * reqid - request id value
+ *
+ * Returns:
+ * none - request id may/may not be set
+ *
+ */
+void
+set_reqid ( resp, reqid )
+ u_char *resp;
+ int reqid;
+{
+ u_char *bp = (u_char *)&resp[18];
+ union {
+ int i;
+ u_char c[4];
+ } u;
+
+#ifndef sun
+ u.i = htonl(reqid);
+#else
+ u.i = reqid;
+#endif /* !sun */
+
+ /*
+ * Replace the current Request ID with the supplied value
+ */
+ UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
+
+ return;
+
+}
+
+/*
+ * Send a generic response packet
+ *
+ * Arguments:
+ * sd - socket to send the reply on
+ * reqid - original request ID from GET PDU
+ * resp - pointer to the response to send
+ *
+ * Returns:
+ * none - response sent
+ *
+ */
+void
+send_resp ( sd, reqid, resp )
+ int sd;
+ int reqid;
+ u_char *resp;
+{
+
+ set_reqid ( resp, reqid );
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "===== Sent %d bytes =====\n", resp[0] );
+ hexdump ( (u_char *)&resp[1], resp[0] );
+ }
+ write ( sd, (caddr_t)&resp[1], resp[0] );
+
+ return;
+}
+
+/*
+ * Initialize information on what physical adapters HARP knows about
+ *
+ * Query the HARP subsystem about configuration and physical interface
+ * information for any currently registered ATM adapters. Store the information
+ * as arrays for easier indexing by SNMP port/index numbers.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none Information from HARP available
+ *
+ */
+void
+init_ilmi()
+{
+ struct air_cfg_rsp *cfg_info = NULL;
+ struct air_intf_rsp *intf_info = NULL;
+ int buf_len;
+
+ /*
+ * Get configuration info - what's available with 'atm sh config'
+ */
+ buf_len = get_cfg_info ( NULL, &cfg_info );
+ /*
+ * If error occurred, clear out everything
+ */
+ if ( buf_len <= 0 ) {
+ UM_ZERO ( Cfg, sizeof(Cfg) );
+ UM_ZERO ( Intf, sizeof(Intf) );
+ NUnits = 0;
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "NUnits: %d\n", NUnits );
+ }
+ return;
+ }
+
+ /*
+ * Move to local storage
+ */
+ UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
+ /*
+ * Compute how many units information was returned for
+ */
+ NUnits = buf_len / sizeof(struct air_cfg_rsp);
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "NUnits: %d\n", NUnits );
+ }
+ /* Housecleaning */
+ free ( cfg_info );
+ cfg_info = NULL;
+ /*
+ * Get the per interface information
+ */
+ buf_len = get_intf_info ( NULL, &intf_info );
+ /*
+ * If error occurred, clear out Intf info
+ */
+ if ( buf_len <= 0 ) {
+ UM_ZERO ( Intf, sizeof(Intf) );
+ return;
+ }
+
+ /*
+ * Move to local storage
+ */
+ UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
+ /* Housecleaning */
+ free ( intf_info );
+ intf_info = NULL;
+
+ return;
+
+}
+
+/*
+ * Open a new SNMP session for ILMI
+ *
+ * Start by updating interface information, in particular, how many
+ * interfaces are in the system. While we'll try to open sessons on
+ * all interfaces, this deamon currently can only handle the first
+ * interface.
+ *
+ * Arguments:
+ * none
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+ilmi_open ()
+{
+ struct sockaddr_atm satm;
+ struct t_atm_aal5 aal5;
+ struct t_atm_traffic traffic;
+ struct t_atm_bearer bearer;
+ struct t_atm_qos qos;
+ struct t_atm_app_name appname;
+ Atm_addr subaddr;
+ char buffer[MAX_LEN+1];
+ char nifname[IFNAMSIZ];
+ int optlen;
+ int unit = 0;
+ struct timer_elem *open_timer,
+ *state_timer;
+ u_char sig_proto;
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "ilmi_open()\n" );
+ }
+ init_ilmi();
+
+ for ( unit = 0; unit < NUnits; unit++ ) {
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "Unit: %d Sig: %d Trap: %d Ilmi: %d\n",
+ unit, Intf[unit].anp_sig_proto, trap_fd[unit],
+ ilmi_fd[unit] );
+ }
+ /*
+ * ILMI only makes sense for UNI signalling protocols
+ */
+ sig_proto = Intf[unit].anp_sig_proto;
+ if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
+ sig_proto != ATM_SIG_UNI40 )
+ continue;
+
+ /*
+ * If we're waiting for a coldStart TRAP, we'll be in trap_fd[],
+ * If we're processing ILMI, we'll be in ilmi_fd[], otherwise,
+ * this unit hasn't been opened yet.
+ */
+ if ( trap_fd[unit] == -1 && ilmi_fd[unit] == -1 ) {
+
+ trap_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
+
+ if ( trap_fd[unit] < 0 ) {
+ perror ( "open" );
+ continue;
+ }
+
+ /*
+ * Set interface name. For now, we must have a netif to go on...
+ */
+ if ( Intf[unit].anp_nif_cnt == 0 ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "No nif on unit %d\n", unit );
+ }
+ close ( trap_fd[unit] );
+ trap_fd[unit] = -1;
+ ilmi_fd[unit] = -1;
+ continue;
+ }
+ sprintf ( nifname, "%s0\0", Intf[unit].anp_nif_pref );
+ optlen = sizeof ( nifname );
+ if ( setsockopt ( trap_fd[unit], T_ATM_SIGNALING,
+ T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
+ perror ( "setsockopt" );
+ if ( Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "Couldn't set interface name \"%s\"\n",
+ nifname );
+ }
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "nifname: closing unit %d\n", unit );
+ }
+ close ( trap_fd[unit] );
+ trap_fd[unit] = -1;
+ ilmi_fd[unit] = -1;
+ continue;
+ }
+
+ /*
+ * Set up destination SAP
+ */
+ UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
+ satm.satm_family = AF_ATM;
+#ifndef sun
+ satm.satm_len = sizeof(satm);
+#endif /* sun */
+
+ satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
+ satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
+ satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
+ satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
+ ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
+ 0 );
+ ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
+ 16 );
+
+ satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
+ satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
+ satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
+
+ satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
+
+ satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
+
+ /*
+ * Set up connection parameters
+ */
+ aal5.forward_max_SDU_size = MAX_LEN;
+ aal5.backward_max_SDU_size = MAX_LEN;
+ aal5.SSCS_type = T_ATM_NULL;
+ optlen = sizeof(aal5);
+ if ( setsockopt ( trap_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
+ (caddr_t) &aal5, optlen ) < 0 ) {
+ perror ( "setsockopt(aal5)" );
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "aal5: closing unit %d\n", unit );
+ }
+ close ( trap_fd[unit] );
+ trap_fd[unit] = -1;
+ ilmi_fd[unit] = -1;
+ continue;
+ }
+
+ traffic.forward.PCR_high_priority = T_ATM_ABSENT;
+ traffic.forward.PCR_all_traffic = 100000;
+ traffic.forward.SCR_high_priority = T_ATM_ABSENT;
+ traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
+ traffic.forward.MBS_high_priority = T_ATM_ABSENT;
+ traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
+ traffic.forward.tagging = T_NO;
+ traffic.backward.PCR_high_priority = T_ATM_ABSENT;
+ traffic.backward.PCR_all_traffic = 100000;
+ traffic.backward.SCR_high_priority = T_ATM_ABSENT;
+ traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
+ traffic.backward.MBS_high_priority = T_ATM_ABSENT;
+ traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
+ traffic.backward.tagging = T_NO;
+ traffic.best_effort = T_YES;
+ optlen = sizeof(traffic);
+ if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
+ (caddr_t)&traffic, optlen) < 0) {
+ perror("setsockopt(traffic)");
+ }
+ bearer.bearer_class = T_ATM_CLASS_X;
+ bearer.traffic_type = T_ATM_NULL;
+ bearer.timing_requirements = T_ATM_NULL;
+ bearer.clipping_susceptibility = T_NO;
+ bearer.connection_configuration = T_ATM_1_TO_1;
+ optlen = sizeof(bearer);
+ if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
+ (caddr_t)&bearer, optlen) < 0) {
+ perror("setsockopt(bearer)");
+ }
+
+ qos.coding_standard = T_ATM_NETWORK_CODING;
+ qos.forward.qos_class = T_ATM_QOS_CLASS_0;
+ qos.backward.qos_class = T_ATM_QOS_CLASS_0;
+ optlen = sizeof(qos);
+ if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
+ optlen) < 0) {
+ perror("setsockopt(qos)");
+ }
+
+ subaddr.address_format = T_ATM_ABSENT;
+ subaddr.address_length = 0;
+ optlen = sizeof(subaddr);
+ if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
+ (caddr_t)&subaddr, optlen) < 0) {
+ perror("setsockopt(dest_sub)");
+ }
+
+ strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
+ optlen = sizeof(appname);
+ if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
+ (caddr_t)&appname, optlen) < 0) {
+ perror("setsockopt(appname)");
+ }
+
+ /*
+ * Now try to connect to destination
+ */
+ if ( connect ( trap_fd[unit], (struct sockaddr *) &satm,
+ sizeof(satm)) < 0 ) {
+ perror ( "connect" );
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "connect: closing unit %d\n", unit );
+ }
+ close ( trap_fd[unit] );
+ trap_fd[unit] = -1;
+ ilmi_fd[unit] = -1;
+ continue;
+ }
+
+ if ( Debug_Level && Log ) {
+ write_timestamp();
+ fprintf ( Log, "***** opened unit %d\n", unit );
+ }
+ /*
+ * Send coldStart TRAP
+ */
+ if ( Debug_Level > 4 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "===== Sent %d bytes =====\n",
+ coldStart_Trap[0] );
+ hexdump ( (u_char *)&coldStart_Trap[1], coldStart_Trap[0] );
+ }
+ if ( Debug_Level && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\tSend coldStart TRAP to unit %d\n", unit );
+ }
+ last_trap[unit] = time ( (time_t *)NULL );
+ write ( trap_fd[unit], (caddr_t)&coldStart_Trap[1],
+ coldStart_Trap[0] );
+ }
+
+ }
+
+ signal ( SIGALRM, ilmi_open );
+ alarm ( SLEEP_TIME );
+
+ return;
+
+}
+
+/*
+ * Send our local IP address for this interface
+ *
+ * Arguments:
+ * s - socket to send message on
+ * hdr - pointer to internal SNMP header
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+send_myipnm ( s, hdr )
+ int s;
+ Snmp_Header *hdr;
+{
+ char intf_name[IFNAMSIZ];
+ int namelen = IFNAMSIZ;
+ struct air_netif_rsp *net_info = NULL;
+ struct sockaddr_in *sin;
+
+ COPY_RESP ( MyIpNm_Resp );
+
+ if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
+ (caddr_t) intf_name, &namelen ) ) {
+ perror ( "Couldn't get socket name" );
+ return;
+ }
+
+ /*
+ * Get network interface information for this physical interface
+ */
+ get_netif_info ( intf_name, &net_info );
+ if ( net_info == NULL )
+ return;
+
+ sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
+
+ /*
+ * Copy interface's IP address into reply packet
+ */
+ UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, (caddr_t)&Resp_Buf[51],
+ 4 );
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\tSend NM IP address\n" );
+ }
+
+ send_resp ( s, hdr->reqid, Resp_Buf );
+
+ /*
+ * Clean up
+ */
+ free ( net_info );
+ return;
+}
+
+/*
+ * Set local NSAP prefix and then reply with our full NSAP address.
+ *
+ * Switch will send a SET message with the NSAP prefix after a coldStart.
+ * We'll set that prefix into HARP and then send a SET message of our own
+ * with our full interface NSAP address.
+ *
+ * Arguments:
+ * oid - objid from SET message
+ * hdr - pointer to internal SNMP header
+ * buf - pointer to SET buffer
+ * s - socket to send messages on
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+set_prefix ( oid, hdr, buf, s )
+ Objid *oid;
+ Snmp_Header *hdr;
+ u_char *buf;
+ int s;
+{
+ struct atmsetreq asr;
+ Atm_addr *aa;
+ int fd;
+ int i;
+ u_char *cpp;
+ int len; /* PDU length before completion */
+
+ /*
+ * If we don't reply to the SET then it keeps getting retransmitted.
+ */
+ buf[14] = PDU_TYPE_GETRESP;
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\tSend SET_RESPONSE\n" );
+ }
+ send_resp ( s, hdr->reqid, buf );
+
+ /*
+ * Build IOCTL request to set prefix
+ */
+ asr.asr_opcode = AIOCS_SET_PRF;
+ strncpy ( asr.asr_prf_intf, Intf[0].anp_intf,
+ sizeof(asr.asr_prf_intf ) );
+ /*
+ * Pull prefix out of received Objid
+ */
+ for ( i = 0; i < oid->oid[13]; i++ )
+ asr.asr_prf_pref[i] = oid->oid[i + 14];
+
+ /*
+ * Pass new prefix to the HARP kernel
+ */
+ fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
+ if ( fd < 0 )
+ return;
+ if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
+ if ( errno != EALREADY ) {
+ syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
+ if ( Log ) {
+ write_timestamp();
+ fprintf ( Log, "ilmid: errno %d setting prefix\n",
+ errno );
+ }
+ return;
+ }
+ }
+ close ( fd );
+
+ /*
+ * Reload the cfg/intf info with newly set prefix
+ */
+ init_ilmi();
+
+ aa = &Intf[0].anp_addr;
+
+ /*
+ * Finish building SET NSAP packet
+ */
+
+ COPY_RESP ( NetPrefix_Resp );
+
+ len = Resp_Buf[0];
+ cpp = &Resp_Buf[len + 1]; /* Set to end of response buffer */
+ len++;
+ *cpp++ = aa->address_length;
+ for ( i = 0; i < aa->address_length; i++ ) {
+ u_char c = ((u_char *)(aa->address))[i];
+
+ if ( c > 127 ) {
+ *cpp++ = ( c >> 7 ) | 0x80;
+ len++;
+ c &= 0x7f;
+ }
+ *cpp++ = c;
+ len++;
+ }
+ /*
+ * Pack "set = 1" onto end
+ */
+ *cpp++ = 0x02;
+ *cpp++ = 0x01;
+ *cpp++ = 0x01;
+ len += 3;
+
+ /*
+ * Go back and patch up lengths...
+ */
+ Resp_Buf[0] = len;
+ Resp_Buf[4] = (u_char)(len - 4);
+ Resp_Buf[15] = (u_char)(len - 15);
+ Resp_Buf[31] = (u_char)(len - 31);
+ Resp_Buf[35] = (u_char)(len - 35);
+ Resp_Buf[37] = (u_char)(len - 40);
+
+ /*
+ * Set reqid
+ */
+ set_reqid ( Resp_Buf, Req_ID++ );
+
+ /*
+ * Send SET
+ */
+ if ( Debug_Level > 2 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "===== Send SET: %d bytes =====\n",
+ Resp_Buf[0] );
+ hexdump ( (u_char *)&Resp_Buf[1], Resp_Buf[0] );
+ }
+ write ( s, (caddr_t)&Resp_Buf[1], Resp_Buf[0] );
+
+ return;
+
+}
+
+Objid oid;
+
+/*
+ * Parse an ASN_TYPE_SET pdu
+ *
+ * Crack apart the various pieces of a SET message. The OBJID being set is
+ * left in oid which is compared and handled else where.
+ *
+ * Arguments:
+ * bp - pointer to current location in PDU buffer
+ *
+ * Returns:
+ * bp - updated buffer pointer
+ * 0 - no error
+ * -1 - error in PDU
+ *
+ */
+int
+process_set ( bp )
+ caddr_t *bp;
+{
+ caddr_t bufp = *bp;
+ int pdulen;
+ int b;
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "SET:: " );
+ }
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ *bp = bufp;
+ return ( -1 );
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ *bp = bufp;
+ return ( -1 );
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be OBJID
+ */
+ if ( *bufp++ != ASN_OBJID ) {
+ *bp = bufp;
+ return ( -1 );
+ }
+ asn_get_objid ( &bufp, &oid );
+ /*
+ * Should be <= value>
+ */
+ switch ( *bufp++ ) {
+ case ASN_INTEGER:
+ b = asn_get_int ( &bufp );
+ if ( Debug_Level > 5 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "Value = %d\n", b );
+ }
+ break;
+ case ASN_OBJID:
+ break;
+ }
+
+ /*
+ * Return updated pointer
+ */
+ *bp = bufp;
+
+ return ( 0 );
+}
+
+int specific_trap;
+int generic_trap;
+int trap_time;
+u_char trap_ip[5];
+Objid trap_oid;
+Objid extra_trap_oid;
+
+/*
+ * Parse an ASN_TYPE_TRAP pdu
+ *
+ * Crack apart the various pieces of a TRAP message. The information elements are
+ * left in global space and used elsewhere if anyone cares (which they currently don't).
+ *
+ * Arguments:
+ * bp - pointer to current location in PDU buffer
+ * sd - socket descriptor pdu arrived on
+ *
+ * Returns:
+ * bp - updated buffer pointer
+ * 0 - no error
+ * -1 - error in PDU
+ *
+ */
+int
+process_trap ( bp, sd )
+ caddr_t *bp;
+ int sd;
+{
+ caddr_t bufp = *bp;
+ int pdulen;
+ int i;
+
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "TRAP:: " );
+ }
+ /*
+ * Should be pdulen
+ */
+ pdulen = *bufp++;
+ /*
+ * Should be OBJID
+ */
+ if ( *bufp++ != ASN_OBJID ) {
+ if ( Log )
+ fprintf ( Log, "\n" );
+ *bp = bufp;
+ return ( -1 );
+ }
+ asn_get_objid ( &bufp, &trap_oid );
+ /*
+ * First oid coded as 40 * X + Y
+ */
+ if ( Debug_Level > 5 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "%d.%d", trap_oid.oid[1] / 40,
+ trap_oid.oid[1] % 40 );
+ for ( i = 2; i <= trap_oid.oid[0]; i++ )
+ fprintf ( Log, ".%d", trap_oid.oid[i] );
+ fprintf ( Log, "\n" );
+ }
+ /*
+ * Should be OCTET STRING
+ */
+ if ( *bufp++ != ASN_IPADDR ) {
+ if ( Debug_Level > 5 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "Expected IP ADDRESS\n" );
+ }
+ *bp = bufp;
+ return ( -1 );
+ }
+ asn_get_octet ( &bufp, trap_ip );
+ if ( Debug_Level > 5 && Log) {
+ write_timestamp();
+ fprintf ( Log, "\tIP: %d.%d.%d.%d",
+ trap_ip[0], trap_ip[1], trap_ip[2], trap_ip[3] );
+ }
+ /*
+ * Should be Generic Trap followed by Specific Trap
+ */
+ if ( *bufp++ != ASN_INTEGER ) {
+ if ( Log )
+ fprintf ( Log, "\n" );
+ *bp = bufp;
+ return ( -1 );
+ }
+ generic_trap = asn_get_int ( &bufp );
+ if ( Debug_Level > 5 && Log ) {
+ fprintf ( Log, " Generic Trap: %s (%d)",
+ Traps[generic_trap], generic_trap );
+ }
+ if ( *bufp++ != ASN_INTEGER ) {
+ if ( Log )
+ fprintf ( Log, "\n" );
+ *bp = bufp;
+ return ( -1 );
+ }
+ specific_trap = asn_get_int ( &bufp );
+ if ( Debug_Level > 5 && Log ) {
+ fprintf ( Log, " Specific Trap: 0x%x\n",
+ specific_trap );
+ }
+ /*
+ * Should be TIMESTAMP
+ */
+ if ( *bufp++ != ASN_TIMESTAMP ) {
+ if ( Log )
+ fprintf ( Log, "\n" );
+ *bp = bufp;
+ return ( -1 );
+ }
+ trap_time = asn_get_int ( &bufp );
+ if ( Debug_Level > 5 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\tTimestamp: %d seconds", trap_time );
+ }
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ *bp = bufp;
+ return ( -1 );
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be OBJID
+ */
+ if ( *bufp++ != ASN_OBJID ) {
+ *bp = bufp;
+ return ( -1 );
+ }
+ asn_get_objid ( &bufp, &extra_trap_oid );
+ if ( Debug_Level > 5 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "\tExtra Objid: " );
+ fprintf ( Log, "%d.%d", extra_trap_oid.oid[1] / 40,
+ extra_trap_oid.oid[1] % 40 );
+ for ( i = 2; i <= extra_trap_oid.oid[0]; i++ )
+ fprintf ( Log, ".%d", extra_trap_oid.oid[i] );
+ fprintf ( Log, "\n" );
+ }
+ /*
+ * Whole thing ended with a NULL
+ */
+ bufp++;
+ bufp++;
+
+ /*
+ * Return updated pointer
+ */
+ *bp = bufp;
+
+ if ( generic_trap == 0 ) {
+ write ( sd, (caddr_t)&coldStart_Trap[1],
+ coldStart_Trap[0] );
+ }
+
+ return ( 0 );
+
+}
+
+u_char No_Such[] = { 37,
+ 0x30, 0x82, 0x00, 0x00,
+ 0x02, 0x01, 0x00,
+ 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49,
+ PDU_TYPE_GETRESP,
+ 0x00,
+ 0x02, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x01, 0x02,
+ 0x02, 0x01, 0x01,
+ 0x30, 0x82, 0x00, 0x00,
+ 0x30, 0x82, 0x00, 0x00,
+ 0x06, 0x00
+ };
+void
+send_no_such ( s, Hdr, op )
+ int s;
+ Snmp_Header *Hdr;
+ Objid *op;
+{
+ u_char *cp, *cpp;
+ int len;
+ int i;
+
+ len = No_Such[0];
+
+ UM_COPY ( No_Such, Resp_Buf, len + 1 );
+
+ cp = cpp = (u_char *)&Resp_Buf[len];
+
+ /*
+ * Copy OID into response buffer
+ */
+ *cp++ = op->oid[0];
+ for ( i = 1; i <= op->oid[0]; i++ ) {
+ u_int c = op->oid[i];
+
+ if ( c > 127 ) {
+ *cp++ = ( c >> 7 ) | 0x80;
+ len++;
+ c &= 0x7f;
+ /*
+ * Increment OID length
+ */
+ *cpp += 1;
+ }
+ *cp++ = c;
+ len++;
+ }
+ /*
+ * Finish off with a NULL
+ */
+ *cp++ = 0x05;
+ *cp++ = 0x00;
+ len += 2;
+
+ /*
+ * Patch up all the length locations
+ */
+ Resp_Buf[0] = len;
+ Resp_Buf[4] = len - 4;
+ Resp_Buf[15] = len - 15;
+ Resp_Buf[31] = len - 31;
+ Resp_Buf[35] = len - 35;
+
+ /*
+ * Send Response
+ */
+ send_resp ( s, Hdr->reqid, Resp_Buf );
+
+ return;
+}
+
+/*
+ * Utility to strip off any leading path information from a filename
+ *
+ * Arguments:
+ * path pathname to strip
+ *
+ * Returns:
+ * fname striped filename
+ *
+ */
+char *
+basename ( path )
+ char *path;
+{
+ char *fname;
+
+ if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
+ fname++;
+ else
+ fname = path;
+
+ return ( fname );
+}
+
+/*
+ * Increment Debug Level
+ *
+ * Catches SIGUSR1 signal and increments value of Debug_Level
+ *
+ * Arguments:
+ * sig - signal number
+ *
+ * Returns:
+ * none - Debug_Level incremented
+ *
+ */
+void
+Increment_DL ( sig )
+ int sig;
+{
+ Debug_Level++;
+ if ( Debug_Level && Log == (FILE *)NULL )
+ if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
+ Log = NULL;
+ else
+ setbuf ( Log, NULL );
+ signal ( SIGUSR1, Increment_DL );
+ alarm ( SLEEP_TIME );
+ return;
+}
+
+/*
+ * Decrement Debug Level
+ *
+ * Catches SIGUSR2 signal and decrements value of Debug_Level
+ *
+ * Arguments:
+ * sig - signal number
+ *
+ * Returns:
+ * none - Debug_Level decremented
+ *
+ */
+void
+Decrement_DL ( sig )
+ int sig;
+{
+ Debug_Level--;
+ if ( Debug_Level <= 0 ) {
+ Debug_Level = 0;
+ if ( Log ) {
+ fclose ( Log );
+ Log = NULL;
+ }
+ }
+ signal ( SIGUSR2, Decrement_DL );
+ alarm ( SLEEP_TIME );
+ return;
+}
+
+main ( argc, argv )
+ int argc;
+ char *argv[];
+{
+ u_char buf[256], set_buf[256];
+ char community[1024];
+ u_char *bufp;
+ int s;
+ int c;
+ int foregnd = 0; /* run in the foreground? */
+ int pdulen;
+ int version;
+ int pdutype;
+ int reqid;
+ int error_status;
+ int error_ptr;
+ int b;
+ int i;
+ int lerr = 0;
+ int Reset = 0; /* Should we send a coldStart and exit? */
+ Snmp_Header *Hdr;
+ int n;
+
+ /*
+ * What are we running as? (argv[0])
+ */
+ progname = strdup ( (char *)basename ( argv[0] ) );
+ /*
+ * What host are we
+ */
+ gethostname ( hostname, sizeof ( hostname ) );
+
+ /*
+ * Ilmid needs to run as root to set prefix
+ */
+ if ( getuid() != 0 ) {
+ fprintf ( stderr, "%s: needs to run as root.\n", progname );
+ exit ( -1 );
+ }
+
+ /*
+ * Parse arguments
+ */
+ while ( ( c = getopt ( argc, argv, "d:fr" ) ) != EOF )
+ switch ( c ) {
+ case 'd':
+ Debug_Level = atoi ( optarg );
+ break;
+ case 'f':
+ foregnd++;
+ break;
+ case 'r':
+ Reset++;
+ break;
+ case '?':
+ fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
+ progname );
+ exit ( -1 );
+/* NOTREACHED */
+ break;
+ }
+
+ /*
+ * If we're not doing debugging, run in the background
+ */
+ if ( foregnd == 0 ) {
+#ifdef sun
+ int pid, fd;
+
+ if ( ( pid = fork() ) < 0 ) {
+ fprintf ( stderr, "fork failed\n" );
+ exit ( 1 );
+ } else if (pid != 0) {
+ /* Parent process - exit and allow child to run */
+ exit ( 0 );
+ }
+ /* Child process */
+ if ( ( lerr = setpgrp ( 0, getpid() ) ) < 0 ) {
+ fprintf ( stderr, "Can't set process group" );
+ exit ( 1 );
+ }
+ if ( ( fd = open ( "/dev/tty", O_RDWR ) ) >= 0 ) {
+ ioctl ( fd, TIOCNOTTY, (char *)NULL );
+ close ( fd );
+ }
+ /* close all open descriptors */
+ for ( fd = 3; fd < getdtablesize(); fd++ )
+ close ( fd );
+#else
+ if ( daemon ( 0, 0 ) )
+ err ( 1, "Can't fork" );
+#endif
+ } else
+ setbuf ( stdout, NULL );
+
+ signal ( SIGUSR1, Increment_DL );
+ signal ( SIGUSR2, Decrement_DL );
+
+ /*
+ * Open log file
+ */
+ if ( Debug_Level )
+ if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
+ Log = NULL;
+ else
+ setbuf ( Log, NULL );
+
+ /*
+ * Get our startup time
+ */
+ (void) gettimeofday ( &starttime, NULL );
+ starttime.tv_sec--;
+ starttime.tv_usec += 1000000;
+
+ /*
+ * Reset all the interface descriptors
+ */
+ for ( i = 0; i < MAX_UNITS; i++ ) {
+ trap_fd[i] = -1;
+ last_trap[i] = (time_t)0;
+ ilmi_fd[i] = -1;
+ }
+ /*
+ * Try to open all the interfaces
+ */
+ ilmi_open ();
+
+ /*
+ * If we're just sending a coldStart end exiting...
+ */
+ if ( Reset ) {
+ for ( i = 0; i < MAX_UNITS; i++ )
+ if ( trap_fd[i] >= 0 ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "Close trap_fd[%d]: %d\n",
+ i, trap_fd[i] );
+ }
+ close ( trap_fd[i] );
+ }
+ exit ( 2 );
+ }
+
+ /*
+ * For ever...
+ */
+ for ( ; ; ) {
+ int maxfd = 0;
+ int count;
+ struct timeval tvp;
+ fd_set rfd;
+ time_t curtime;
+
+ ilmi_open();
+
+ /*
+ * SunOS CC doesn't allow automatic aggregate initialization.
+ * Make everybody happy and do it here...
+ */
+ tvp.tv_sec = 15;
+ tvp.tv_usec = 0;
+
+ curtime = time ( (time_t *)NULL );
+
+ /*
+ * Check for TRAP messages
+ */
+ FD_ZERO ( &rfd );
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "Check Traps: " );
+ }
+ for ( i = 0; i < MAX_UNITS; i++ ) {
+ if ( Debug_Level > 1 && Log )
+ fprintf ( Log, "trap_fd[%d]: %d ", i, trap_fd[i] );
+ if ( trap_fd[i] != -1 ) {
+ /*
+ * If we haven't sent a coldStart trap recently,
+ * send one now
+ */
+ if ( last_trap[i] + TRAP_TIME < curtime ) {
+ last_trap[i] = curtime;
+ /*
+ * Send coldStart TRAP
+ */
+ if ( Debug_Level > 4 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "===== Sent %d bytes =====\n",
+ coldStart_Trap[0] );
+ hexdump ( (u_char *)&coldStart_Trap[1],
+ coldStart_Trap[0] );
+ }
+ if ( Debug_Level && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\tSend coldStart TRAP to unit %d\n", i );
+ }
+ write ( trap_fd[i], (caddr_t)&coldStart_Trap[1],
+ coldStart_Trap[0] );
+ }
+ if ( (trap_fd[i] >= 0) &&
+ FD_SET ( trap_fd[i], &rfd )) {
+ maxfd = MAX ( maxfd, trap_fd[i] );
+ }
+ }
+ }
+ if ( Debug_Level > 1 && Log )
+ fprintf ( Log, "maxfd: %d\n", maxfd );
+
+ if ( maxfd ) {
+ count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
+
+ if ( count > 0 ) {
+ for ( i = 0; i < MAX_UNITS; i++ ) {
+ if ( trap_fd[i] >= 0 && FD_ISSET ( trap_fd[i], &rfd ) ) {
+ s = trap_fd[i];
+
+ n = read ( s, (caddr_t)&buf[1], sizeof(buf) - 1 );
+ if ( n == -1 && ( errno == ECONNRESET ||
+ errno == EBADF ) ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "Bad read: close trap_fd[%d]: %d\n",
+ i, trap_fd[i] );
+ }
+ close ( trap_fd[i] );
+ trap_fd[i] = -1;
+ ilmi_fd[i] = -1;
+ }
+ if ( n ) {
+ buf[0] = n;
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "***** Read %d bytes *****\n",
+ n );
+ hexdump ( (caddr_t)&buf[1], n );
+ }
+ bufp = buf;
+ /*
+ * Skip length byte
+ */
+ bufp++;
+ /*
+ * Crack the header
+ */
+ if ( ( Hdr = asn_get_header ( &bufp ) ) == NULL )
+ continue;
+ pdutype = Hdr->pdutype;
+ /*
+ * Only interested in TRAP messages
+ */
+ switch ( pdutype ) {
+ /*
+ * FORE switches often go straight to SET prefix
+ * after receiving a coldStart TRAP from us
+ */
+ case PDU_TYPE_SET:
+ /*
+ * Make a copy of this PDU so that a
+ * SET NSAP prefix can reply to it.
+ */
+ UM_COPY ( buf, set_buf, sizeof(buf) );
+
+ lerr = process_set ( &bufp );
+ /*
+ * Can't do a simple oid_cmp since we
+ * don't yet know what the prefix is.
+ * If it looks like a SET netPrefix.0,
+ * then compare the portion leading up
+ * to the NSAP prefix part.
+ */
+ if ( oid.oid[0] == 26 ) {
+ oid.oid[0] = 12;
+ if ( oid_cmp ( &setprefix, &oid ) == 0 ) {
+ oid.oid[0] = 26;
+ set_prefix ( &oid, Hdr, set_buf, s );
+ }
+ }
+ /*
+ * We now move from awaiting TRAP to processing ILMI
+ */
+ ilmi_fd[i] = trap_fd[i];
+ trap_fd[i] = -1;
+ break;
+ case PDU_TYPE_TRAP:
+ lerr = process_trap ( &bufp, trap_fd[i] );
+ /*
+ * We now move from awaiting TRAP to processing ILMI
+ */
+ ilmi_fd[i] = trap_fd[i];
+ trap_fd[i] = -1;
+ break;
+ }
+ } /* if n */
+ } /* if FD_ISSET */
+ } /* for i */
+ } /* if count */
+ }
+
+ /*
+ * Reset from TRAP checking
+ */
+ maxfd = 0;
+ errno = 0;
+ /*
+ * Check for ILMI messages
+ */
+ FD_ZERO ( &rfd );
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "Check Ilmis: " );
+ }
+ for ( i = 0; i < MAX_UNITS; i++ ) {
+ if ( Debug_Level > 1 && Log )
+ fprintf ( Log, "ilmi_fd[%d]: %d ", i, ilmi_fd[i] );
+ if ( ilmi_fd[i] != -1 ) {
+ if ( (ilmi_fd[i] >= 0) &&
+ FD_SET ( ilmi_fd[i], &rfd )) {
+ maxfd = MAX ( maxfd, ilmi_fd[i] );
+ }
+ }
+ }
+ if ( Debug_Level > 1 && Log )
+ fprintf ( Log, "maxfd: %d\n", maxfd );
+
+ if ( maxfd ) {
+ count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
+
+ if ( count > 0 ) {
+ for ( i = 0; i < MAX_UNITS; i++ ) {
+ if ( ilmi_fd[i] >= 0 && FD_ISSET ( ilmi_fd[i], &rfd ) ) {
+
+ s = ilmi_fd[i];
+
+ n = read ( s, (caddr_t)&buf[1], sizeof(buf) - 1 );
+ if ( n == -1 && ( errno == ECONNRESET ||
+ errno == EBADF ) ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "Bad read: close ilmi_fd[%d]: %d\n",
+ i, ilmi_fd[i] );
+ }
+ close ( ilmi_fd[i] );
+ trap_fd[i] = -1;
+ ilmi_fd[i] = -1;
+ }
+ if ( n ) {
+ buf[0] = n;
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "***** Read %d bytes *****\n",
+ n );
+ hexdump ( (caddr_t)&buf[1], n );
+ }
+ bufp = buf;
+ /*
+ * Skip length byte
+ */
+ bufp++;
+ /*
+ * Crack the header
+ */
+ if ( ( Hdr = asn_get_header ( &bufp ) )
+ == NULL )
+ continue;
+ pdutype = Hdr->pdutype;
+
+ /*
+ * Do the operation...
+ */
+ switch ( pdutype ) {
+
+ case PDU_TYPE_GET:
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "GET:: " );
+ }
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ lerr = 1;
+ break;
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ lerr = 1;
+ break;
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be OBJID
+ */
+ if ( *bufp++ != ASN_OBJID ) {
+ lerr = 1;
+ break;
+ }
+ asn_get_objid ( &bufp, &oid );
+ /*
+ * Ended with a NULL
+ */
+ bufp++;
+ bufp++;
+ /*
+ * If GET sysObjId.0
+ */
+ if (oid_cmp(&sysObjId, &oid) == 0 ) {
+ send_resp ( s, Hdr->reqid,
+ sysObjId_Resp );
+
+ } else
+ /*
+ * If GET sysUpTime.0
+ */
+ if (oid_cmp(&sysUpTime, &oid) == 0 ) {
+ send_uptime_resp ( s,
+ Hdr->reqid );
+ } else
+ /*
+ * If GET myIpNm.0
+ */
+ if ( oid_cmp ( &myipnm, &oid ) == 0 ) {
+ send_myipnm ( s, Hdr );
+ } else
+ /*
+ * If GET uniType.0
+ */
+ if ( oid_cmp ( &unitype, &oid ) == 0 ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\tSend uniType\n" );
+ }
+ send_resp ( s, Hdr->reqid,
+ UniType_Resp );
+ } else
+ /*
+ * If GET uniVer.0
+ */
+ if ( oid_cmp ( &univer, &oid ) == 0 ) {
+ int p = UniVer_Resp[0];
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\tSend uniVer\n" );
+ }
+ switch (Intf[i].anp_sig_proto) {
+ case ATM_SIG_UNI30:
+ UniVer_Resp[p] =
+ UNIVER_UNI30;
+ break;
+ case ATM_SIG_UNI31:
+ UniVer_Resp[p] =
+ UNIVER_UNI31;
+ break;
+ case ATM_SIG_UNI40:
+ UniVer_Resp[p] =
+ UNIVER_UNI40;
+ break;
+ }
+ send_resp ( s, Hdr->reqid,
+ UniVer_Resp );
+ } else
+ /*
+ * If GET devType.0
+ */
+ if ( oid_cmp ( &devtype, &oid ) == 0 ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\tSend devType\n" );
+ }
+ send_resp ( s, Hdr->reqid,
+ DevType_Resp );
+ } else
+ /*
+ * If GET foreSigGrp....0
+ */
+ if (oid_cmp(&foresiggrp, &oid) == 0) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\tSend noSuchVar\n" );
+ }
+ send_resp ( s, Hdr->reqid,
+ NoSuchFore_Resp );
+ } else
+ if ( oid_cmp(&layeridx, &oid) == 0 ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\t*** LayerIndex\n" );
+ }
+ } else
+ if ( oid_cmp(&maxvcc, &oid) == 0 ) {
+ send_resp ( s, Hdr->reqid,
+ maxVCC_Resp );
+ } else
+ if ( oid_cmp ( &portidx, &oid ) == 0 ) {
+ int p = PortIndex_Resp[0];
+ PortIndex_Resp[p] = i + 1;
+ send_resp ( s, Hdr->reqid,
+ PortIndex_Resp );
+ } else
+ send_no_such ( s, Hdr, &oid );
+ break;
+
+ case PDU_TYPE_GETNEXT:
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log, "GET_NEXT:: " );
+ }
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ lerr = 1;
+ break;
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be SEQUENCE OF
+ */
+ if ( *bufp++ != ASN_SEQUENCE ) {
+ lerr = 1;
+ break;
+ }
+ pdulen = asn_get_pdu_len ( &bufp );
+ /*
+ * Should be OBJID
+ */
+ if ( *bufp++ != ASN_OBJID ) {
+ lerr = 1;
+ break;
+ }
+ asn_get_objid ( &bufp, &oid );
+ /*
+ * Ended with a NULL
+ */
+ bufp++;
+ bufp++;
+ /*
+ * If this is a GET_NEXT netPrefix then
+ * the other side probably restarted
+ * and is looking for a table empty
+ * indication before restarting the
+ * ILMI protocol.
+ */
+ if ( oid_cmp(&netpfx_oid, &oid) == 0 ) {
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "\tSend GET_RESP:\n" );
+ }
+ send_resp ( s, Hdr->reqid,
+ GetNext_Resp );
+ }
+ break;
+
+ case PDU_TYPE_GETRESP:
+ if ( Debug_Level > 1 && Log ) {
+ write_timestamp();
+ fprintf ( Log,
+ "GET_RESP:: \n" );
+ }
+ /*
+ * Ignore any responses to our GETs.
+ * (We don't send any GETs.)
+ */
+ break;
+
+ case PDU_TYPE_SET:
+ /*
+ * Make a copy of this PDU so that a
+ * SET NSAP prefix can reply to it.
+ */
+ UM_COPY ( buf, set_buf, sizeof(buf) );
+
+ if ( process_set ( &bufp ) < 0 )
+ break;
+
+ /*
+ * Can't do a simple oid_cmp since we
+ * don't know what the prefix is yet.
+ * If it looks like a SET netPrefix.0,
+ * then compare the portion leading up
+ * to the NSAP prefix part.
+ */
+ if ( oid.oid[0] == 26 ) {
+ oid.oid[0] = 12;
+ if ( oid_cmp(&setprefix,&oid)
+ == 0 ) {
+ oid.oid[0] = 26;
+ set_prefix ( &oid, Hdr,
+ set_buf, s );
+ }
+ }
+ break;
+
+ case PDU_TYPE_TRAP:
+ lerr = process_trap ( &bufp, s );
+ break;
+ }
+ /*
+ * Forget about this PDU
+ */
+ free ( Hdr );
+ Hdr = NULL;
+
+ } /* end of read(s) */
+ } /* end if FD_ISSET(s) */
+ } /* end of for ( i... */
+ } /* end of if ( count ) */
+ } else {
+ sleep ( SLEEP_TIME );
+ }
+ } /* end of for ever */
+
+}
+