3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
31 * Implement very minimal ILMI address registration.
33 * Implement very crude and basic support for "cracking" and
34 * "encoding" SNMP PDU's to support ILMI prefix and NSAP address
35 * registration. Code is not robust nor is it meant to provide any
36 * "real" SNMP support. Much of the code expects predetermined values
37 * and will fail if anything else is found. Much of the "encoding" is
38 * done with pre-computed PDU's.
40 * See "The Simple Book", Marshall T. Rose, particularly chapter 5,
41 * for ASN and BER information.
45 #include <sys/param.h>
46 #include <sys/socket.h>
47 #include <sys/sockio.h>
49 #include <netinet/in.h>
50 #include <netatm/port.h>
51 #include <netatm/atm.h>
52 #include <netatm/atm_if.h>
53 #include <netatm/atm_sigmgr.h>
54 #include <netatm/atm_sap.h>
55 #include <netatm/atm_sys.h>
56 #include <netatm/atm_ioctl.h>
57 #include <dev/hfa/fore_aali.h>
58 #include <dev/hfa/fore_slave.h>
59 #include <dev/hfa/fore_stats.h>
74 __RCSID("@(#) $FreeBSD$");
83 * Define some ASN types
85 #define ASN_INTEGER 0x02
86 #define ASN_OCTET 0x04
88 #define ASN_OBJID 0x06
89 #define ASN_SEQUENCE 0x30
90 #define ASN_IPADDR 0x40
91 #define ASN_TIMESTAMP 0x43
93 static const char *Var_Types[] = {
104 * Define SNMP PDU types
106 #define PDU_TYPE_GET 0xA0
107 #define PDU_TYPE_GETNEXT 0xA1
108 #define PDU_TYPE_GETRESP 0xA2
109 #define PDU_TYPE_SET 0xA3
110 #define PDU_TYPE_TRAP 0xA4
112 static const char *const PDU_Types[] = {
125 #define TRAP_COLDSTART 0
126 #define TRAP_WARMSTART 1
127 #define TRAP_LINKDOWN 2
128 #define TRAP_LINKUP 3
129 #define TRAP_AUTHFAIL 4
130 #define TRAP_EGPLOSS 5
131 #define TRAP_ENTERPRISE 6
134 * Define SNMP Version numbers
136 #define SNMP_VERSION_1 1
137 #define SNMP_VERSION_2 2
140 * SNMP Error-status values
142 #define SNMP_ERR_NOERROR 0
143 #define SNMP_ERR_TOOBIG 1
144 #define SNMP_ERR_NOSUCHNAME 2
145 #define SNMP_ERR_BADVALUE 3
146 #define SNMP_ERR_READONLY 4
147 #define SNMP_ERR_GENERR 5
150 * Max string length for Variable
157 #define VAR_UNKNOWN -1
160 * Define our internal representation of an OBJECT IDENTIFIER
165 typedef struct objid Objid;
168 * Define a Veriable classso that we can handle multiple GET/SET's
171 typedef struct variable Variable;
176 int ival; /* INTEGER/TIMESTAMP */
177 Objid oval; /* OBJID */
178 long aval; /* IPADDR */
179 char sval[STRLEN]; /* OCTET */
185 * Every SNMP PDU has the first four fields of this header. The only type
186 * which doesn't have the last three fields is the TRAP type.
194 /* GET/GETNEXT/GETRESP/SET */
209 typedef struct snmp_header Snmp_Header;
211 Snmp_Header *ColdStart_Header;
212 Snmp_Header *PDU_Header;
215 * Define some OBJET IDENTIFIERS that we'll try to reply to:
217 * sysUpTime: number of time ticks since this deamon came up
218 * netpfx_oid: network prefix table
219 * unitype: is this a PRIVATE or PUBLIC network link
220 * univer: which version of UNI are we running
221 * devtype: is this a USER or NODE ATM device
222 * setprefix: used when the switch wants to tell us its NSAP prefix
223 * foresiggrp: FORE specific Objid we see alot of (being connected to FORE
228 {{ 8, 43, 6, 1, 2, 1, 1, 2, 0 }},
229 #define UPTIME_OBJID 1
230 {{ 8, 43, 6, 1, 2, 1, 1, 3, 0 }},
232 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 1, 0 }},
234 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 2, 0 }},
235 #define LAYER_OBJID 4
236 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 1, 0 }},
237 #define MAXVCC_OBJID 5
238 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 3, 0 }},
239 #define UNITYPE_OBJID 6
240 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 8, 0 }},
241 #define UNIVER_OBJID 7
242 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 9, 0 }},
243 #define DEVTYPE_OBJID 8
244 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 10, 0 }},
245 #define ADDRESS_OBJID 9
246 {{ 8, 43, 6, 1, 4, 1, 353, 2, 6 }},
247 #define NETPFX_OBJID 10
248 {{ 9, 43, 6, 1, 4, 1, 353, 2, 7, 1 }},
250 {{ 7, 43, 6, 1, 4, 1, 9999, 1 }},
251 #define SETPFX_OBJID 12 /* ATM Forum says 1=valid, 2=invalid, not 0! */
252 {{ 12, 43, 6, 1, 4, 1, 353, 2, 7, 1, 1, 3, 0 }},
253 #define ENTERPRISE_OBJID 13
254 {{ 8, 43, 6, 1, 4, 1, 3, 1, 1 }},
255 #define ATMF_PORTID 14
256 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 4, 0 }},
257 #define ATMF_SYSID 15
258 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 8, 0 }},
259 #define MADGE_OBJECT1 16 /* I don't have a clue ... -RH */
260 {{ 9, 43, 6, 1, 4, 1, 353, 2, 7, 99 }},
263 #define NUM_OIDS (sizeof(Objids)/sizeof(Objid))
265 #define UNIVER_UNI20 1
266 #define UNIVER_UNI30 2
267 #define UNIVER_UNI31 3
268 #define UNIVER_UNI40 4
269 #define UNIVER_UNKNOWN 5
271 #define UNITYPE_PUBLIC 1
272 #define UNITYPE_PRIVATE 2
274 #define DEVTYPE_USER 1
275 #define DEVTYPE_NODE 2
277 /* For print_pdu() */
282 * ILMI protocol states
285 ILMI_UNKNOWN, /* Uninitialized */
286 ILMI_COLDSTART, /* We need to send a COLD_START trap */
287 ILMI_INIT, /* Ensure that switch has reset */
288 ILMI_REG, /* Looking for SET message */
289 ILMI_RUNNING /* Normal processing */
292 static const char *ILMI_State[] = {
301 * Our (incrementing) Request ID
306 * Temporary buffer for building response packets. Should help ensure
307 * that we aren't accidently overwriting some other memory.
309 u_char Resp_Buf[1024];
312 * Copy the reponse into a buffer we can modify without
313 * changing the original...
315 #define COPY_RESP(resp) \
316 bcopy ( (resp), Resp_Buf, (resp)[0] + 1 )
321 * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests
323 int ilmi_fd[MAX_UNITS + 1];
325 * enum ilmi_states for this unit
327 int ilmi_state[MAX_UNITS + 1];
329 * Local copy for HARP physical configuration information
331 struct air_cfg_rsp Cfg[MAX_UNITS + 1];
333 * Local copy for HARP interface configuration information
335 struct air_int_rsp Intf[MAX_UNITS + 1];
340 Objid addressEntry[MAX_UNITS + 1];
343 * When this daemon started
345 struct timeval starttime;
348 int foregnd = 0; /* run in the foreground? */
353 /* File to write debug messages to */
354 #define LOG_FILE "/var/log/ilmid"
355 FILE *Log; /* File descriptor for log messages */
357 static const char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
358 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
361 * function declarations
363 static void write_timestamp (void);
364 static void hexdump (FILE *, u_int8_t *, int, char *);
365 static int asn_get_pdu_len (u_char **, int *);
366 static int asn_get_encoded (u_char **, int *);
367 static int asn_get_int (u_char **, int *);
368 static void asn_set_int (u_char **, int);
369 static void print_objid (Objid *);
370 static void asn_get_objid (u_char **, Objid *, int *);
371 static int asn_put_objid (u_char **, Objid *);
372 static void asn_get_octet (u_char **, char *, int *);
373 static void print_header (Snmp_Header *);
374 static void parse_oids (Snmp_Header *, u_char **);
375 static int oid_cmp (Objid *, Objid *);
376 static int oid_ncmp (Objid *, Objid *, int);
377 static int find_var (Variable *);
378 static int get_ticks (void);
379 static void build_pdu (Snmp_Header *, int);
380 static void free_pdu (Snmp_Header *);
381 static void print_pdu (int, int, Snmp_Header *, int, u_char *);
382 static void send_resp (int, Snmp_Header *, u_char *);
383 static void init_ilmi (void);
384 static void ilmi_open (void);
385 static void get_local_ip (int, long *);
386 static void set_prefix (Objid *, Snmp_Header *, int);
387 static void set_address (Snmp_Header *, int);
388 static void process_get (Snmp_Header *, int);
389 static int lmi_object_find (Variable *);
390 static int lmi_rcvcmd_getnext(Snmp_Header *, int);
391 static int lmi_rcvcmd_trap (Snmp_Header *, int);
392 static void ilmi_do_state (void);
393 static void Increment_DL (int);
394 static void Decrement_DL (int);
396 static Snmp_Header * asn_get_header (u_char **);
397 static Snmp_Header * build_cold_start (void);
398 static Snmp_Header * build_generic_header (void);
401 * Write a syslog() style timestamp
403 * Write a syslog() style timestamp with month, day, time and hostname
414 write_timestamp (void)
419 clk = time ( (time_t)NULL );
420 tm = localtime ( &clk );
422 if ( Log && Debug_Level > 1 )
424 fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
425 Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
426 tm->tm_sec, hostname );
433 * Utility to pretty print buffer as hex dumps
437 * ptr - buffer pointer
438 * len - length to pretty print
439 * desc - output header
446 hexdump (out, ptr, len, desc)
459 fprintf(out, "[ %s (%d bytes)]\n", desc, len);
461 bzero(line, sizeof(line));
463 for (i = 0, j = 0; i < len; i++) {
465 if (j == 0) fprintf(out, "%04x: ", i);
466 if (j == 8) fprintf(out, "| ");
468 fprintf(out, "%02x ", ptr[i]);
469 line[j] = isalnum(ptr[i]) ? ptr[i] : '.' ;
471 fprintf(out, " |%16s|\n", line);
472 bzero(line, sizeof(line));
479 if (j <= 8) fprintf(out, " ");
480 for (; j < 16; j++) fprintf(out, " ");
481 fprintf(out, " |%-16s|\n", line);
489 * Get lengths from PDU encodings
491 * Lengths are sometimes encoded as a single byte if the length
492 * is less the 127 but are more commonly encoded as one byte with
493 * the high bit set and the lower seven bits indicating the nuber
494 * of bytes which make up the length value. Trailing data is (to my
495 * knowledge) not 7-bit encoded.
498 * bufp - pointer to buffer pointer
499 * plen - pointer to PDU length or NULL if not a concern
502 * bufp - updated buffer pointer
503 * plen - (possibly) adjusted pdu length
504 * <len> - decoded length
508 asn_get_pdu_len (u_char **bufp, int *plen)
518 for ( i = 0; i < (b & ~0x80); i++ ) {
519 len = len * 256 + *bp++;
531 * Get an 7-bit encoded value.
533 * Get a value which is represented using a 7-bit encoding. The last
534 * byte in the stream has the high-bit clear.
537 * bufp - pointer to the buffer pointer
538 * len - pointer to the buffer length
541 * bufp - updated buffer pointer
542 * len - updated buffer length
543 * <val> - value encoding represented
547 asn_get_encoded (u_char **bufp, int *len)
554 * Keep going while high bit is set
558 * Each byte can represent 7 bits
560 val = ( val << 7 ) + ( *bp & ~0x80 );
562 } while ( *bp++ & 0x80 );
564 *bufp = bp; /* update buffer pointer */
565 *len = l; /* update buffer length */
571 * Get a BER encoded integer
573 * Intergers are encoded as one byte length followed by <length> data bytes
576 * bufp - pointer to the buffer pointer
577 * plen - pointer to PDU length or NULL if not a concern
580 * bufp - updated buffer pointer
581 * plen - (possibly) updated PDU length
582 * <val> - value of encoded integer
586 asn_get_int (u_char **bufp, int *plen)
596 for ( i = 0; i < len; i++ ) {
597 v = (v * 256) + *bp++;
606 * Set a BER encoded integer
609 * bufp - pointer to buffer pointer where we are to set int in
610 * val - integer value to set
614 * <bufp> - updated buffer pointer
618 asn_set_int (u_char **bufp, int val)
624 int len = sizeof(int);
628 /* Check for special case where val == 0 */
638 while ( u.c[i] == 0 && i++ < sizeof(int) )
641 if ( u.c[i] > 0x7f ) {
647 bcopy ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
655 * Utility to print an object identifier.
658 * objid - pointer to objid representation
665 print_objid (Objid *objid)
670 * First oid coded as 40 * X + Y
674 fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
675 objid->oid[1] % 40 );
677 for ( i = 2; i <= objid->oid[0]; i++ )
679 fprintf ( Log, ".%d", objid->oid[i] );
681 fprintf ( Log, "\n" );
687 * Get Object Identifier
690 * bufp - pointer to buffer pointer
691 * objid - pointer to objid buffer
692 * plen - pointer to PDU length or NULL of not a concern
695 * bufp - updated buffer pointer
696 * objid - internal representation of encoded objid
697 * plen - (possibly) adjusted PDU length
701 asn_get_objid (u_char **bufp, Objid *objid, int *plen)
705 int *ip = (int *)objid + 1; /* First byte will contain length */
712 *ip++ = asn_get_encoded ( &bp, &len );
717 objid->oid[0] = oidlen;
724 * Put OBJID - assumes elements <= 16383 for two byte coding
728 asn_put_objid (u_char **bufp, Objid *objid)
736 *bp++ = objid->oid[0];
738 for ( i = 1; i <= objid->oid[0]; i++ ) {
739 u_int c = objid->oid[i];
742 *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
744 c &= 0x7f; /* XXX - assumption of two bytes */
759 * Octet strings are encoded as a 7-bit encoded length followed by <len>
763 * bufp - pointer to buffer pointer
764 * octet - pointer to octet buffer
765 * plen - pointer to PDU length
768 * bufp - updated buffer pointer
769 * octet - encoded Octet String
770 * plen - (possibly) adjusted PDU length
774 asn_get_octet (u_char **bufp, char *octet, int *plen)
781 * &i is really a dummy value here as we don't keep track
782 * of the ongoing buffer length
784 len = asn_get_encoded ( &bp, &i );
786 for ( i = 0; i < len; i++ ) {
799 * Utility to print SNMP PDU header information
802 * Hdr - pointer to internal SNMP header structure
809 print_header (Snmp_Header *Hdr)
816 " PDU Type: 0x%x (%s)\n"
819 " Community: \"%s\"\n",
820 Hdr->pdutype, PDU_Types[Hdr->pdutype & 7],
825 if (Hdr->pdutype != PDU_TYPE_TRAP) {
830 " Error Index: %d\n",
841 fprintf ( Log, "Variable Type: %d", var->type );
842 if ( Var_Types[var->type] )
843 fprintf ( Log, " (%s)", Var_Types[var->type] );
844 fprintf ( Log, "\n Object: ");
845 print_objid ( &var->oid );
846 fprintf ( Log, " Value: ");
847 switch ( var->type ) {
849 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
852 fprintf ( Log, "NULL" );
855 fprintf ( Log, "[0x%x]", var->type );
858 fprintf ( Log, "\n" );
868 * Pull OID's from GET/SET message
871 * h - pointer to Snmp_Header
872 * bp - pointer to input PDU
879 parse_oids (Snmp_Header *h, u_char **bp)
887 if ( *bufp++ == ASN_SEQUENCE ) {
890 /* Create new Variable instance */
891 if ( ( var = (Variable *)malloc(sizeof(Variable)) ) == NULL )
896 bzero(var, sizeof(Variable));
900 /* Set head iff NULL */
901 if ( h->head == NULL ) {
907 /* Get length of variable sequence */
908 sublen = asn_get_pdu_len ( &bufp, &len );
909 /* Should be OBJID type */
910 if ( *bufp++ != ASN_OBJID ) {
914 asn_get_objid ( (u_char **)&bufp, &var->oid, &len );
917 switch ( var->type ) {
919 var->var.ival = asn_get_int ( &bufp, &len );
926 asn_get_objid ( &bufp, &var->var.oval, &len );
929 asn_get_octet ( &bufp, var->var.sval, &len );
934 fprintf ( Log, "Unknown variable type: %d\n",
949 * Crack the SNMP header
951 * Pull the PDU length, SNMP version, SNMP community and PDU type.
952 * If present, also pull out the Request ID, Error status, and Error
956 * bufp - pointer to buffer pointer
959 * bufp - updated buffer pointer
960 * - generated SNMP header
964 asn_get_header (u_char **bufp)
972 * Allocate memory to hold the SNMP header
974 if ( ( h = (Snmp_Header *)malloc(sizeof(Snmp_Header)) ) == NULL )
975 return ( (Snmp_Header *)NULL );
978 * Ensure that we wipe the slate clean
980 bzero(h, sizeof(Snmp_Header));
983 * PDU has to start as SEQUENCE OF
985 if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
986 return ( (Snmp_Header *)NULL );
989 * Get the length of remaining PDU data
991 h->pdulen = asn_get_pdu_len ( &bp, NULL );
994 * We expect to find an integer encoding Version-1
996 if ( *bp++ != ASN_INTEGER ) {
997 return ( (Snmp_Header *)NULL );
999 h->version = asn_get_int ( &bp, NULL );
1002 * After the version, we need the community name
1004 if ( *bp++ != ASN_OCTET ) {
1005 return ( (Snmp_Header *)NULL );
1007 asn_get_octet ( &bp, h->community, NULL );
1010 * Single byte PDU type
1015 * If this isn't a TRAP PDU, then look for the rest of the header
1017 if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
1019 (void) asn_get_pdu_len ( &bp, &dummy );
1022 if ( *bp++ != ASN_INTEGER ) {
1024 return ( (Snmp_Header *)NULL );
1026 h->reqid = asn_get_int ( &bp, NULL );
1029 if ( *bp++ != ASN_INTEGER ) {
1031 return ( (Snmp_Header *)NULL );
1033 h->error = asn_get_int ( &bp, NULL );
1036 if ( *bp++ != ASN_INTEGER ) {
1038 return ( (Snmp_Header *)NULL );
1040 h->erridx = asn_get_int ( &bp, NULL );
1042 /* Sequence of... */
1043 if ( *bp++ != ASN_SEQUENCE ) {
1045 return ( (Snmp_Header *)NULL );
1047 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
1048 h->varlen += ( len - 1 );
1050 parse_oids ( h, &bp );
1060 * Compare two internal OID representations
1063 * oid1 - Internal Object Identifier
1064 * oid2 - Internal Object Identifier
1068 * 1 - Objid's don't match
1072 oid_cmp (Objid *oid1, Objid *oid2)
1080 if ( !(oid1->oid[0] == oid2->oid[0] ) )
1081 /* Different lengths */
1087 * value by value compare
1089 for ( i = 1; i <= len; i++ ) {
1090 if ( !(oid1->oid[i] == oid2->oid[i]) )
1091 /* values don't match */
1095 /* Objid's are identical */
1100 * Compare two internal OID representations
1103 * oid1 - Internal Object Identifier
1104 * oid2 - Internal Object Identifier
1105 * len - Length of OID to compare
1109 * 1 - Objid's don't match
1113 oid_ncmp (Objid *oid1, Objid *oid2, int len)
1118 * value by value compare
1120 for ( i = 1; i <= len; i++ ) {
1121 if ( !(oid1->oid[i] == oid2->oid[i]) )
1122 /* values don't match */
1126 /* Objid's are identical */
1131 * Find the index of an OBJID which matches this Variable instance.
1134 * var - pointer to Variable instance
1137 * idx - index of matched Variable instance
1138 * -1 - no matching Variable found
1142 find_var (Variable *var)
1146 for ( i = 0; i < NUM_OIDS; i++ )
1147 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1156 * Return the time process has been running as a number of ticks
1168 struct timeval timenow;
1169 struct timeval timediff;
1171 (void) gettimeofday ( &timenow, NULL );
1173 * Adjust for subtraction
1176 timenow.tv_usec += 1000000;
1179 * Compute time since 'starttime'
1181 timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1182 timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1185 * Adjust difference timeval
1187 if ( timediff.tv_usec >= 1000000 ) {
1188 timediff.tv_usec -= 1000000;
1193 * Compute number of ticks
1195 return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1200 * Build a response PDU
1203 * hdr - pointer to PDU Header with completed Variable list
1210 build_pdu (Snmp_Header *hdr, int type)
1212 u_char *bp = Resp_Buf;
1223 * Clear out the reply
1225 bzero ( Resp_Buf, sizeof(Resp_Buf) );
1227 /* [0] is reserved for overall length */
1230 /* Start with SEQUENCE OF */
1231 *bp++ = ASN_SEQUENCE;
1232 /* - assume we can code length in two octets */
1237 *bp++ = ASN_INTEGER;
1238 asn_set_int ( &bp, hdr->version );
1239 /* Community name */
1241 *bp++ = strlen ( hdr->community );
1242 bcopy ( hdr->community, bp, strlen ( hdr->community ) );
1243 bp += strlen ( hdr->community );
1247 /* Length of OID data - assume it'll fit in one octet */
1250 if ( type != PDU_TYPE_TRAP ) {
1252 *bp++ = ASN_INTEGER;
1253 asn_set_int ( &bp, hdr->reqid );
1255 * Check to see if all the vaiables were resolved - we do this
1256 * by looking for something which still has an ASN_NULL value.
1259 if ( type == PDU_TYPE_GETRESP ) {
1260 while ( var && erridx == 0 ) {
1261 if ( var->type != ASN_NULL ) {
1270 *bp++ = ASN_INTEGER;
1271 *bp++ = 0x01; /* length = 1 */
1273 *bp++ = SNMP_ERR_NOSUCHNAME;
1275 *bp++ = SNMP_ERR_NOERROR;
1277 *bp++ = ASN_INTEGER;
1278 *bp++ = 0x01; /* length = 1 */
1279 *bp++ = erridx; /* index == 0 if no error */
1281 /* type == PDU_TYPE_TRAP */
1283 /* Fill in ENTERPRISE OBJID */
1285 (void) asn_put_objid ( &bp, &hdr->enterprise );
1287 /* Fill in IP address */
1289 *bp++ = sizeof ( hdr->ipaddr );
1290 bcopy ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1291 bp += sizeof(hdr->ipaddr);
1293 /* Fill in generic and specific trap types */
1294 *bp++ = ASN_INTEGER;
1295 asn_set_int ( &bp, hdr->generic_trap );
1296 *bp++ = ASN_INTEGER;
1297 asn_set_int ( &bp, hdr->specific_trap );
1299 /* Fill in time-stamp - assume 0 for now */
1300 *bp++ = ASN_TIMESTAMP;
1301 asn_set_int ( &bp, 0 );
1303 /* encoded length */
1304 traplen = ( bp - ppp - 1 );
1306 /* Continue with variable processing */
1310 *bp++ = ASN_SEQUENCE;
1312 /* - assume we can code length in two octets */
1318 /* Install Variables */
1326 *bp++ = ASN_SEQUENCE;
1328 /* - assume we can code length in two octets */
1336 len += asn_put_objid ( &bp, &var->oid );
1338 if ( erridx && varidx >= erridx ) {
1339 /* Code this variable as NULL */
1350 switch ( var->type ) {
1352 asn_set_int ( &bp, var->var.ival );
1353 len += ( *lpp + 1 );
1356 *bp++ = var->var.sval[0];
1358 bcopy ( (caddr_t)&var->var.sval[1],
1359 bp, var->var.sval[0] );
1360 len += var->var.sval[0];
1361 bp += var->var.sval[0];
1368 len += asn_put_objid ( &bp, &var->var.oval );
1375 bcopy ( (caddr_t)&var->var.aval, bp, 4 );
1380 asn_set_int ( &bp, var->var.ival );
1381 len += ( *lpp + 1 );
1388 /* Accumulate total Variable sequence length */
1389 varlen += (len + 4);
1391 /* Fill in length of this sequence */
1392 bpp[1] = len & 0xff;
1399 /* Fill in length of Variable sequence */
1400 vpp[1] = varlen & 0xff;
1401 vpp[0] = varlen >> 8;
1403 if ( type != PDU_TYPE_TRAP ) {
1404 /* Fill in length of data AFTER PDU type */
1405 *ppp = varlen + 12 + ppp[2]; /* + length of reqid */
1407 /* Fill in length of data AFTER PDU type */
1408 *ppp = varlen + traplen + 4; /* + length of initial sequence of */
1411 /* Fill in overall sequence length */
1412 pdulen = *ppp + 7 + strlen ( hdr->community );
1413 Resp_Buf[4] = pdulen & 0x7f;
1414 Resp_Buf[3] = pdulen >> 8;
1416 pdulen = bp - Resp_Buf - 1;
1418 Resp_Buf[0] = pdulen;
1420 hdr->pdutype = type;
1421 hdr->pdulen = pdulen;
1427 free_pdu (Snmp_Header *hdr)
1431 while ( hdr->head ) {
1432 var = hdr->head->next; /* Save next link */
1433 free ( hdr->head ); /* Free current var */
1434 hdr->head = var; /* Set head to next link */
1437 free ( hdr ); /* Free fixed portion */
1441 print_pdu (int dir, int intf, Snmp_Header *Hdr, int len, u_char *buf)
1443 const char * pdu_dir;
1444 const char * pdu_type;
1457 pdu_dir = "undefined";
1462 pdu_type = "unknown";
1465 pdu_type = PDU_Types[Hdr->pdutype & 7];
1466 pdu_num = Hdr->pdutype;
1470 "%s: %s(%d), ILMI %s(%d), PDU Type %s(0x%x) %d/%d bytes.\n",
1472 Intf[intf].anp_intf, ilmi_fd[intf],
1473 ILMI_State[intf], ilmi_state[intf],
1478 fprintf(Log, "Header seems to be invalid.\n");
1482 hexdump(Log, (u_char *)&buf[1], len, NULL);
1488 * Send a generic response packet
1491 * sd - socket to send the reply on
1492 * reqid - original request ID from GET PDU
1493 * resp - pointer to the response to send
1496 * none - response sent
1500 send_resp (int intf, Snmp_Header *Hdr, u_char *resp)
1504 if ( ilmi_fd[intf] > 0 ) {
1505 n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1506 if ( Log && Debug_Level > 1 ) {
1507 print_pdu(PDU_SEND, intf, Hdr, n, resp);
1516 * Build a COLD_START TRAP PDU
1519 static Snmp_Header *
1520 build_cold_start (void)
1525 hdr = (Snmp_Header *)malloc(sizeof(Snmp_Header));
1527 fprintf(stderr, "malloc() failed in %s()\n", __func__);
1530 bzero(hdr, sizeof(Snmp_Header));
1533 hdr->version = SNMP_VERSION_1 - 1;
1534 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1536 hdr->ipaddr = 0x0; /* 0.0.0.0 */
1537 hdr->generic_trap = TRAP_COLDSTART;
1538 hdr->specific_trap = 0;
1539 bcopy ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1542 hdr->head = (Variable *)malloc(sizeof(Variable));
1544 fprintf(stderr, "malloc() failed in %s()\n", __func__);
1547 bzero(hdr->head, sizeof(Variable));
1550 bcopy ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1552 var->type = ASN_NULL;
1558 * Build a Generic PDU Header
1561 static Snmp_Header *
1562 build_generic_header (void)
1566 hdr = (Snmp_Header *)malloc(sizeof(Snmp_Header));
1568 fprintf(stderr, "malloc() failed in %s()\n", __func__);
1571 bzero(hdr, sizeof(Snmp_Header));
1574 hdr->version = SNMP_VERSION_1 - 1;
1575 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1581 * Initialize information on what physical adapters HARP knows about
1583 * Query the HARP subsystem about configuration and physical interface
1584 * information for any currently registered ATM adapters. Store the information
1585 * as arrays for easier indexing by SNMP port/index numbers.
1591 * none Information from HARP available
1597 struct air_cfg_rsp *cfg_info = NULL;
1598 struct air_int_rsp *intf_info = NULL;
1602 * Get configuration info - what's available with 'atm sh config'
1604 buf_len = get_cfg_info ( NULL, &cfg_info );
1606 * If error occurred, clear out everything
1608 if ( buf_len <= 0 ) {
1609 bzero ( Cfg, sizeof(Cfg) );
1610 bzero( Intf, sizeof(Intf) );
1616 * Move to local storage
1618 bcopy ( cfg_info, (caddr_t)Cfg, buf_len );
1620 * Compute how many units information was returned for
1622 NUnits = buf_len / sizeof(struct air_cfg_rsp);
1627 * Get the per interface information
1629 buf_len = get_intf_info ( NULL, &intf_info );
1631 * If error occurred, clear out Intf info
1633 if ( buf_len <= 0 ) {
1634 bzero ( Intf, sizeof(Intf) );
1639 * Move to local storage
1641 bcopy ( intf_info, (caddr_t)Intf, buf_len );
1651 * Open a new SNMP session for ILMI
1653 * Start by updating interface information, in particular, how many
1654 * interfaces are in the system. While we'll try to open sessons on
1655 * all interfaces, this deamon currently can only handle the first
1668 struct sockaddr_atm satm;
1669 struct t_atm_aal5 aal5;
1670 struct t_atm_traffic traffic;
1671 struct t_atm_bearer bearer;
1672 struct t_atm_qos qos;
1673 struct t_atm_app_name appname;
1675 char nifname[IFNAMSIZ];
1682 for ( unit = 0; unit < NUnits; unit++ ) {
1685 * ILMI only makes sense for UNI signalling protocols
1687 sig_proto = Intf[unit].anp_sig_proto;
1688 if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1689 sig_proto != ATM_SIG_UNI40 )
1692 if ( ilmi_fd[unit] == -1 ) {
1694 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1696 if ( ilmi_fd[unit] < 0 ) {
1702 * Set interface name. For now, we must have a netif to go on...
1704 if ( Intf[unit].anp_nif_cnt == 0 ) {
1705 if ( Debug_Level > 1 && Log ) {
1707 fprintf ( Log, "No nif on unit %d\n", unit );
1709 close ( ilmi_fd[unit] );
1713 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1714 optlen = sizeof ( nifname );
1715 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1716 T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1717 perror ( "setsockopt" );
1721 "Couldn't set interface name \"%s\"\n",
1724 if ( Debug_Level > 1 && Log ) {
1726 fprintf ( Log, "nifname: closing unit %d\n", unit );
1728 close ( ilmi_fd[unit] );
1734 * Set up destination SAP
1736 bzero ( (caddr_t) &satm, sizeof(satm) );
1737 satm.satm_family = AF_ATM;
1738 #if (defined(BSD) && (BSD >= 199103))
1739 satm.satm_len = sizeof(satm);
1742 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1743 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1744 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1745 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1746 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1748 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1751 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1752 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1753 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1755 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1757 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1760 * Set up connection parameters
1762 aal5.forward_max_SDU_size = MAX_LEN;
1763 aal5.backward_max_SDU_size = MAX_LEN;
1764 aal5.SSCS_type = T_ATM_NULL;
1765 optlen = sizeof(aal5);
1766 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1767 (caddr_t) &aal5, optlen ) < 0 ) {
1768 perror ( "setsockopt(aal5)" );
1769 if ( Debug_Level > 1 && Log ) {
1771 fprintf ( Log, "aal5: closing unit %d\n", unit );
1773 close ( ilmi_fd[unit] );
1778 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1779 traffic.forward.PCR_all_traffic = 100000;
1780 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1781 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1782 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1783 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1784 traffic.forward.tagging = T_NO;
1785 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1786 traffic.backward.PCR_all_traffic = 100000;
1787 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1788 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1789 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1790 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1791 traffic.backward.tagging = T_NO;
1792 traffic.best_effort = T_YES;
1793 optlen = sizeof(traffic);
1794 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1795 (caddr_t)&traffic, optlen) < 0) {
1796 perror("setsockopt(traffic)");
1798 bearer.bearer_class = T_ATM_CLASS_X;
1799 bearer.traffic_type = T_ATM_NULL;
1800 bearer.timing_requirements = T_ATM_NULL;
1801 bearer.clipping_susceptibility = T_NO;
1802 bearer.connection_configuration = T_ATM_1_TO_1;
1803 optlen = sizeof(bearer);
1804 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1805 (caddr_t)&bearer, optlen) < 0) {
1806 perror("setsockopt(bearer)");
1809 qos.coding_standard = T_ATM_NETWORK_CODING;
1810 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1811 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1812 optlen = sizeof(qos);
1813 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1815 perror("setsockopt(qos)");
1818 subaddr.address_format = T_ATM_ABSENT;
1819 subaddr.address_length = 0;
1820 optlen = sizeof(subaddr);
1821 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1822 (caddr_t)&subaddr, optlen) < 0) {
1823 perror("setsockopt(dest_sub)");
1826 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1827 optlen = sizeof(appname);
1828 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1829 (caddr_t)&appname, optlen) < 0) {
1830 perror("setsockopt(appname)");
1834 * Now try to connect to destination
1836 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1837 sizeof(satm)) < 0 ) {
1838 perror ( "connect" );
1839 if ( Debug_Level > 1 && Log ) {
1841 fprintf ( Log, "connect: closing unit %d\n", unit );
1843 close ( ilmi_fd[unit] );
1848 if ( Debug_Level && Log ) {
1850 fprintf ( Log, "***** opened unit %d\n", unit );
1853 ilmi_state[unit] = ILMI_COLDSTART;
1864 * Get our local IP address for this interface
1867 * s - socket to find address for
1868 * aval - pointer to variable to store address in
1875 get_local_ip (int s, long *aval)
1877 char intf_name[IFNAMSIZ];
1878 socklen_t namelen = IFNAMSIZ;
1879 struct air_netif_rsp *net_info = NULL;
1880 struct sockaddr_in *sain;
1883 * Get physical interface name
1885 if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1886 (caddr_t) intf_name, &namelen ) )
1890 * Get network interface information for this physical interface
1892 get_netif_info ( intf_name, &net_info );
1893 if ( net_info == NULL )
1896 sain = (struct sockaddr_in *)(void *)&net_info->anp_proto_addr;
1901 bcopy ( (caddr_t)&sain->sin_addr.s_addr, aval, 4 );
1910 * Set local NSAP prefix and then reply with our full NSAP address.
1912 * Switch will send a SET message with the NSAP prefix after a coldStart.
1913 * We'll set that prefix into HARP and then send a SET message of our own
1914 * with our full interface NSAP address.
1917 * oid - objid from SET message
1918 * hdr - pointer to internal SNMP header
1919 * buf - pointer to SET buffer
1920 * s - socket to send messages on
1927 set_prefix (Objid *oid, Snmp_Header *hdr __unused, int intf)
1929 struct atmsetreq asr;
1935 * Build IOCTL request to set prefix
1937 asr.asr_opcode = AIOCS_SET_PRF;
1938 strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1939 sizeof(asr.asr_prf_intf ) );
1941 * Pull prefix out of received Objid
1942 * save in set_prefix IOCTL and addressEntry table
1944 for ( i = 0; i < oid->oid[13]; i++ ) {
1945 asr.asr_prf_pref[i] = oid->oid[i + 14];
1949 * Pass new prefix to the HARP kernel
1951 fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1954 if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1955 if ( errno != EALREADY ) {
1956 syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1959 fprintf ( Log, "errno %d setting prefix\n",
1969 * Reload the cfg/intf info with newly set prefix
1973 aa = &Intf[intf].anp_addr;
1976 * Copy our NSAP into addressEntry table
1979 addressEntry[intf].oid[0] = 0;
1980 for ( i = 0; i < aa->address_length; i++ ) {
1981 addressEntry[intf].oid[0]++; /* Increment length */
1982 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1991 set_address (Snmp_Header *hdr __unused, int intf)
1996 PDU_Header = build_generic_header();
1998 PDU_Header->head = (Variable *)malloc(sizeof(Variable));
1999 if (PDU_Header->head == NULL) {
2000 fprintf(stderr, "malloc() failed in %s()\n", __func__);
2003 bzero(PDU_Header->head, sizeof(Variable));
2005 var = PDU_Header->head;
2006 /* Copy generic addressEntry OBJID */
2007 bcopy ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2009 /* Set specific instance */
2010 i = var->oid.oid[0] + 1; /* Get length */
2011 var->oid.oid[i++] = 1;
2012 var->oid.oid[i++] = 1;
2013 var->oid.oid[i++] = 3;
2014 var->oid.oid[i++] = 0;
2016 /* Copy in address length */
2017 var->oid.oid[i++] = addressEntry[intf].oid[0];
2019 /* Copy in address */
2020 for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
2021 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
2022 var->oid.oid[0] = i - 1; /* Set new length */
2025 var->type = ASN_INTEGER;
2028 build_pdu ( PDU_Header, PDU_TYPE_SET );
2029 send_resp ( intf, PDU_Header, Resp_Buf );
2033 * Increment Debug Level
2035 * Catches SIGUSR1 signal and increments value of Debug_Level
2038 * sig - signal number
2041 * none - Debug_Level incremented
2045 Increment_DL (int sig __unused)
2048 if ( Debug_Level && Log == (FILE *)NULL ) {
2052 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2056 setbuf ( Log, NULL );
2058 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
2061 signal ( SIGUSR1, Increment_DL );
2066 * Decrement Debug Level
2068 * Catches SIGUSR2 signal and decrements value of Debug_Level
2071 * sig - signal number
2074 * none - Debug_Level decremented
2078 Decrement_DL (int sig __unused)
2081 if ( Debug_Level <= 0 ) {
2085 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
2091 signal ( SIGUSR2, Decrement_DL );
2096 * Loop through GET variable list looking for matches
2100 process_get (Snmp_Header *hdr, int intf)
2110 /* Handle the 'GET PREFIX' request */
2111 oidlen = Objids[SETPFX_OBJID].oid[0];
2112 if (oid_ncmp(&var->oid, &Objids[SETPFX_OBJID], oidlen) == 0) {
2113 var->var.ival = 2; /* assume not valid */
2114 for(x = 0; x < 13; x++)
2115 if (var->oid.oid[oidlen + x + 2] !=
2116 addressEntry[intf].oid[x + 1])
2121 hdr->head->var.ival = 1;
2126 idx = find_var ( var );
2129 /* reply with NO SUCH OBJECT */
2130 var->type = ASN_NULL;
2133 var->type = ASN_OBJID;
2134 bcopy ( (caddr_t)&Objids[MY_OBJID],
2135 (caddr_t)&var->var.oval,
2139 var->type = ASN_TIMESTAMP;
2140 var->var.ival = get_ticks();
2143 var->type = ASN_INTEGER;
2144 var->var.ival = UNITYPE_PRIVATE;
2147 var->type = ASN_INTEGER;
2148 switch ( Intf[intf].anp_sig_proto ) {
2150 var->var.ival = UNIVER_UNI30;
2153 var->var.ival = UNIVER_UNI31;
2156 var->var.ival = UNIVER_UNI40;
2159 var->var.ival = UNIVER_UNKNOWN;
2164 var->type = ASN_INTEGER;
2165 var->var.ival = DEVTYPE_USER;
2168 var->type = ASN_INTEGER;
2169 var->var.ival = 1024;
2172 var->type = ASN_INTEGER;
2173 var->var.ival = intf + 1;
2176 var->type = ASN_IPADDR;
2177 get_local_ip( ilmi_fd[intf], &var->var.aval );
2182 var->type = ASN_INTEGER;
2183 var->var.ival = 0x30 + intf;
2186 var->type = ASN_OCTET;
2187 var->var.sval[0] = 6;
2188 bcopy ( (caddr_t)&Cfg[intf].acp_macaddr,
2189 (caddr_t)&var->var.sval[1], 6 );
2197 build_pdu ( hdr, PDU_TYPE_GETRESP );
2198 send_resp ( intf, hdr, Resp_Buf );
2202 /******************************************************************************
2204 * Find an OBJID from known ones
2206 * in: Variable with valid OID
2207 * out: OID number (index), -1 = not found
2210 lmi_object_find (Variable *var)
2217 obj_var = &var->oid;
2219 for (x = 0; x < NUM_OIDS; x++) {
2220 obj_cur = &Objids[x];
2221 for (y = 0; y < 128; y++) {
2222 if (obj_var->oid[y] != obj_cur->oid[y])
2224 if (obj_var->oid[y] == 0) /* object ID endmark */
2233 /******************************************************************************
2235 * Append instance number to OID
2237 * in: Variable, instance number
2238 * out: zero = success
2242 lmi_object_instance (Variable *var, int instnum)
2247 oidptr = var->oid.oid;
2248 curlen = oidptr[0]; /* current length */
2252 oidptr[curlen] = instnum;
2258 /******************************************************************************
2260 * Handle received GETNEXT
2262 * in: Header with valid fields, interface number
2263 * out: zero = success
2267 lmi_rcvcmd_getnext (Snmp_Header *header, int intf)
2274 oidnum = lmi_object_find(header->head);
2275 oidptr = header->head->oid.oid;
2279 /* Should be because the remote side is attempting
2280 * to verify that our table is empty
2283 if ( addressEntry[intf].oid[0] ) {
2285 /* Our table is not empty - return address */
2289 /* Madge Collage sends GETNEXT for this */
2291 if(addressEntry[intf].oid[0]) { /* we have a prefix */
2293 oidptr += oidlen; /* skip to last number */
2295 *oidptr++ = 13; /* length of prefix */
2297 /* fill in the prefix */
2298 for(x = 0; x < 13; x++) {
2299 *oidptr++ = addressEntry[intf].oid[x+1];
2301 header->head->type = ASN_INTEGER;
2302 /* 1=valid, 2=invalid -- only 2 values */
2303 header->head->var.ival = 1;
2304 } else { /* no prefix available */
2305 header->head->type = ASN_NULL;
2310 return (1); /* unknown object ID */
2313 build_pdu(header, PDU_TYPE_GETRESP);
2314 send_resp(intf, header, Resp_Buf);
2320 /******************************************************************************
2322 * Handle received TRAP
2324 * in: Header with valid fields, interface number
2325 * out: zero = success
2329 lmi_rcvcmd_trap (Snmp_Header *header __unused, int intf)
2332 bzero((caddr_t)&addressEntry[intf], sizeof(Objid));
2337 * ILMI State Processing Loop
2361 * SunOS CC doesn't allow automatic aggregate initialization.
2362 * Initialize to zero which effects a poll operation.
2368 * Clear fd_set and initialize to check this interface
2371 for ( intf = 0; intf < MAX_UNITS; intf++ )
2372 if ( ilmi_fd[intf] > 0 ) {
2373 FD_SET ( ilmi_fd[intf], &rfd );
2374 maxfd = MAX ( maxfd, ilmi_fd[intf] );
2378 * Check for new interfaces
2382 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2384 * Do any pre-message state processing
2386 switch ( ilmi_state[intf] ) {
2387 case ILMI_COLDSTART:
2389 * Clear addressTable
2391 bzero ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2394 * Start by sending a COLD_START trap. This should cause the
2395 * remote end to clear the associated prefix/address table(s).
2397 /* Build ColdStart TRAP header */
2398 ColdStart_Header = build_cold_start();
2399 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2400 send_resp ( intf, ColdStart_Header, Resp_Buf );
2403 * Start a timeout so that if the next state fails, we re-enter
2408 /* Enter new state */
2409 ilmi_state[intf] = ILMI_INIT;
2410 /* fall into ILMI_INIT */
2414 * After a COLD_START, we need to check that the remote end has
2415 * cleared any tables. Send a GET_NEXT request to check for this.
2416 * In the event that the table is not empty, or that no reply is
2417 * received, return to COLD_START state.
2419 PDU_Header = build_generic_header();
2421 PDU_Header->head = (Variable *)malloc(sizeof(Variable));
2422 if (PDU_Header->head == NULL) {
2423 fprintf(stderr, "malloc() failed in %s()\n", __func__);
2426 bzero(PDU_Header->head, sizeof(Variable));
2428 var = PDU_Header->head;
2429 bcopy ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2431 var->type = ASN_NULL;
2435 * Send GETNEXT request looking for empty ATM Address Table
2437 PDU_Header->reqid = Req_ID++;
2438 build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2439 send_resp ( intf, PDU_Header, Resp_Buf );
2442 * Start a timeout while looking for SET message. If we don't receive
2443 * a SET, then go back to COLD_START state.
2449 /* Normal SNMP processing */
2457 count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2459 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2461 * Check for received messages
2463 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2465 n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2466 if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2467 ilmi_state[intf] = ILMI_COLDSTART;
2468 close ( ilmi_fd[intf] );
2472 Hdr = asn_get_header(&bpp);
2474 if ( Log && Debug_Level > 1 )
2475 print_pdu(PDU_RECV, intf, Hdr, n, buf);
2480 /* What we do with this messages depends upon the state we're in */
2481 switch ( ilmi_state[intf] ) {
2482 case ILMI_COLDSTART:
2483 /* We should never be in this state here */
2487 /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2488 switch ( Hdr->pdutype ) {
2489 case PDU_TYPE_GETNEXT:
2490 lmi_rcvcmd_getnext(Hdr, intf);
2492 case PDU_TYPE_GETRESP:
2494 * This should be in response to our GETNEXT.
2495 * Check the OIDs and go onto ILMI_RUNNING if
2496 * the address table is empty. We can cheat and
2497 * not check sequence numbers because we only send
2498 * the one GETNEXT request and ILMI says we shouldn't
2499 * have interleaved sessions.
2502 * First look for empty table. If found, go to next state.
2504 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2505 ((Hdr->error == SNMP_ERR_NOERROR) &&
2506 ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2507 Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2508 ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2509 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2511 * Check to see if this matches our address
2512 * and if so, that it's a VALID entry.
2518 aa = &Intf[intf].anp_addr;
2519 if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2520 for ( l = 0; l < aa->address_length; l++ ) {
2521 if ( (int)((u_char *)(aa->address))[l] !=
2522 Hdr->head->oid.oid[14 + l] ) {
2528 if ( Hdr->head->var.ival == 1 ) {
2529 ilmi_state[intf] = ILMI_RUNNING;
2536 /* Look for SET_PREFIX Objid */
2537 if ( oid_ncmp ( &Hdr->head->oid,
2538 &Objids[SETPFX_OBJID],
2539 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2540 set_prefix ( &Hdr->head->oid, Hdr, intf );
2541 /* Reply to SET before sending our ADDRESS */
2542 build_pdu(Hdr, PDU_TYPE_GETRESP);
2543 send_resp( intf, Hdr, Resp_Buf );
2544 set_address ( Hdr, intf );
2546 build_pdu(Hdr, PDU_TYPE_GETRESP);
2547 send_resp( intf, Hdr, Resp_Buf );
2551 /* Remote side wants us to start fresh */
2552 lmi_rcvcmd_trap(Hdr, intf);
2564 /* We'll take anything here */
2565 switch ( Hdr->pdutype ) {
2567 process_get ( Hdr, intf );
2569 case PDU_TYPE_GETRESP:
2570 /* Ignore GETRESPs */
2573 case PDU_TYPE_GETNEXT:
2574 lmi_rcvcmd_getnext(Hdr, intf);
2577 /* Look for SET_PREFIX Objid */
2578 if ( oid_ncmp ( &Hdr->head->oid,
2579 &Objids[SETPFX_OBJID],
2580 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2581 set_prefix ( &Hdr->head->oid, Hdr, intf );
2582 /* Reply to SET before sending our ADDRESS */
2583 build_pdu(Hdr, PDU_TYPE_GETRESP);
2584 send_resp( intf, Hdr, Resp_Buf );
2585 set_address ( Hdr, intf );
2587 build_pdu(Hdr, PDU_TYPE_GETRESP);
2588 send_resp( intf, Hdr, Resp_Buf );
2592 lmi_rcvcmd_trap(Hdr, intf);
2603 } /* if received message */
2604 } /* for each interface */
2605 } /* for ever loop */
2610 main (int argc, char *argv[])
2614 int Reset = 0; /* Should we send a coldStart and exit? */
2617 * What are we running as? (argv[0])
2619 progname = strdup ( (char *)basename ( argv[0] ) );
2623 gethostname ( hostname, sizeof ( hostname ) );
2626 * Ilmid needs to run as root to set prefix
2628 if ( getuid() != 0 ) {
2629 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2636 while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2639 Debug_Level = atoi ( optarg );
2648 fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2656 * If we're not doing debugging, run in the background
2658 if ( foregnd == 0 ) {
2659 if ( daemon ( 0, 0 ) )
2660 err ( 1, "Can't fork" );
2662 setbuf ( stdout, NULL ); */
2664 signal ( SIGUSR1, Increment_DL );
2665 signal ( SIGUSR2, Decrement_DL );
2670 if ( Debug_Level ) {
2674 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2679 setbuf ( Log, NULL );
2682 * Get our startup time
2684 (void) gettimeofday ( &starttime, NULL );
2686 starttime.tv_usec += 1000000;
2688 /* Randomize starting request ID */
2689 Req_ID = starttime.tv_sec;
2692 * Reset all the interface descriptors
2694 for ( i = 0; i < MAX_UNITS; i++ ) {
2698 * Try to open all the interfaces
2703 * If we're just sending a coldStart end exiting...
2706 for ( i = 0; i < MAX_UNITS; i++ )
2707 if ( ilmi_fd[i] >= 0 ) {
2708 /* Build ColdStart TRAP header */
2709 ColdStart_Header = build_cold_start();
2710 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2711 send_resp ( i, ColdStart_Header, Resp_Buf );
2712 if ( Debug_Level > 1 && Log ) {
2714 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2717 close ( ilmi_fd[i] );