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.
26 * @(#) $FreeBSD: src/sbin/atm/ilmid/ilmid.c,v 1.6.2.2 2001/03/04 07:15:30 kris Exp $
27 * @(#) $DragonFly: src/sbin/atm/ilmid/ilmid.c,v 1.5 2003/11/03 19:51:04 eirikn Exp $
34 * Implement very minimal ILMI address registration.
36 * Implement very crude and basic support for "cracking" and
37 * "encoding" SNMP PDU's to support ILMI prefix and NSAP address
38 * registration. Code is not robust nor is it meant to provide any
39 * "real" SNMP support. Much of the code expects predetermined values
40 * and will fail if anything else is found. Much of the "encoding" is
41 * done with pre-computed PDU's.
43 * See "The Simple Book", Marshall T. Rose, particularly chapter 5,
44 * for ASN and BER information.
48 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
52 #include <netinet/in.h>
53 #include <netatm/port.h>
54 #include <netatm/atm.h>
55 #include <netatm/atm_if.h>
56 #include <netatm/atm_sigmgr.h>
57 #include <netatm/atm_sap.h>
58 #include <netatm/atm_sys.h>
59 #include <netatm/atm_ioctl.h>
60 #include <dev/atm/hea/eni_stats.h>
61 #include <dev/atm/hfa/fore_aali.h>
62 #include <dev/atm/hfa/fore_slave.h>
63 #include <dev/atm/hfa/fore_stats.h>
80 * Define some ASN types
82 #define ASN_INTEGER 0x02
83 #define ASN_OCTET 0x04
85 #define ASN_OBJID 0x06
86 #define ASN_SEQUENCE 0x30
87 #define ASN_IPADDR 0x40
88 #define ASN_TIMESTAMP 0x43
90 static char *Var_Types[] = { "", "", "ASN_INTEGER", "", "ASN_OCTET", "ASN_NULL", "ASN_OBJID" };
93 * Define SNMP PDU types
95 #define PDU_TYPE_GET 0xA0
96 #define PDU_TYPE_GETNEXT 0xA1
97 #define PDU_TYPE_GETRESP 0xA2
98 #define PDU_TYPE_SET 0xA3
99 #define PDU_TYPE_TRAP 0xA4
101 static char *PDU_Types[] = { "GET REQUEST", "GETNEXT REQUEST", "GET RESPONSE", "SET REQUEST",
107 #define TRAP_COLDSTART 0
108 #define TRAP_WARMSTART 1
109 #define TRAP_LINKDOWN 2
110 #define TRAP_LINKUP 3
111 #define TRAP_AUTHFAIL 4
112 #define TRAP_EGPLOSS 5
113 #define TRAP_ENTERPRISE 6
116 * Define SNMP Version numbers
118 #define SNMP_VERSION_1 1
119 #define SNMP_VERSION_2 2
122 * SNMP Error-status values
124 #define SNMP_ERR_NOERROR 0
125 #define SNMP_ERR_TOOBIG 1
126 #define SNMP_ERR_NOSUCHNAME 2
127 #define SNMP_ERR_BADVALUE 3
128 #define SNMP_ERR_READONLY 4
129 #define SNMP_ERR_GENERR 5
132 * Max string length for Variable
139 #define VAR_UNKNOWN -1
142 * Define our internal representation of an OBJECT IDENTIFIER
147 typedef struct objid Objid;
150 * Define a Veriable classso that we can handle multiple GET/SET's
153 typedef struct variable Variable;
158 int ival; /* INTEGER/TIMESTAMP */
159 Objid oval; /* OBJID */
160 long aval; /* IPADDR */
161 char sval[STRLEN]; /* OCTET */
167 * Every SNMP PDU has the first four fields of this header. The only type
168 * which doesn't have the last three fields is the TRAP type.
176 /* GET/GETNEXT/GETRESP/SET */
191 typedef struct snmp_header Snmp_Header;
193 Snmp_Header *ColdStart_Header;
194 Snmp_Header *PDU_Header;
197 * Define some OBJET IDENTIFIERS that we'll try to reply to:
199 * sysUpTime: number of time ticks since this deamon came up
200 * netpfx_oid: network prefix table
201 * unitype: is this a PRIVATE or PUBLIC network link
202 * univer: which version of UNI are we running
203 * devtype: is this a USER or NODE ATM device
204 * setprefix: used when the switch wants to tell us its NSAP prefix
205 * foresiggrp: FORE specific Objid we see alot of (being connected to FORE
210 {{ 8, 43, 6, 1, 2, 1, 1, 2, 0 }},
211 #define UPTIME_OBJID 1
212 {{ 8, 43, 6, 1, 2, 1, 1, 3, 0 }},
214 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 1, 0 }},
216 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 2, 0 }},
217 #define LAYER_OBJID 4
218 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 1, 0 }},
219 #define MAXVCC_OBJID 5
220 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 3, 0 }},
221 #define UNITYPE_OBJID 6
222 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 8, 0 }},
223 #define UNIVER_OBJID 7
224 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 9, 0 }},
225 #define DEVTYPE_OBJID 8
226 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 10, 0 }},
227 #define ADDRESS_OBJID 9
228 {{ 8, 43, 6, 1, 4, 1, 353, 2, 6 }},
229 #define NETPFX_OBJID 10
230 {{ 9, 43, 6, 1, 4, 1, 353, 2, 7, 1 }},
232 {{ 7, 43, 6, 1, 4, 1, 9999, 1 }},
233 #define SETPFX_OBJID 12
234 {{ 12, 43, 6, 1, 4, 1, 353, 2, 7, 1, 1, 3, 0 }},
235 #define ENTERPRISE_OBJID 13
236 {{ 8, 43, 6, 1, 4, 1, 3, 1, 1 }},
237 #define ATMF_PORTID 14
238 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 4, 0 }},
239 #define ATMF_SYSID 15
240 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 8, 0 }},
243 #define NUM_OIDS (sizeof(Objids)/sizeof(Objid))
245 #define UNIVER_UNI20 1
246 #define UNIVER_UNI30 2
247 #define UNIVER_UNI31 3
248 #define UNIVER_UNI40 4
249 #define UNIVER_UNKNOWN 5
251 #define UNITYPE_PUBLIC 1
252 #define UNITYPE_PRIVATE 2
254 #define DEVTYPE_USER 1
255 #define DEVTYPE_NODE 2
258 * ILMI protocol states
261 ILMI_UNKNOWN, /* Uninitialized */
262 ILMI_COLDSTART, /* We need to send a COLD_START trap */
263 ILMI_INIT, /* Ensure that switch has reset */
264 ILMI_REG, /* Looking for SET message */
265 ILMI_RUNNING /* Normal processing */
269 * Our (incrementing) Request ID
274 * Temporary buffer for building response packets. Should help ensure
275 * that we aren't accidently overwriting some other memory.
277 u_char Resp_Buf[1024];
280 * Copy the reponse into a buffer we can modify without
281 * changing the original...
283 #define COPY_RESP(resp) \
284 UM_COPY ( (resp), Resp_Buf, (resp)[0] + 1 )
287 * TRAP generic trap types
289 char *Traps[] = { "coldStart", "warmStart", "linkDown", "linkUp",
290 "authenticationFailure", "egpNeighborLoss",
291 "enterpriseSpecific" };
297 * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests
299 int ilmi_fd[MAX_UNITS + 1];
301 * enum ilmi_states for this unit
303 int ilmi_state[MAX_UNITS + 1];
305 * Local copy for HARP physical configuration information
307 struct air_cfg_rsp Cfg[MAX_UNITS + 1];
309 * Local copy for HARP interface configuration information
311 struct air_int_rsp Intf[MAX_UNITS + 1];
316 Objid addressEntry[MAX_UNITS + 1];
319 * When this daemon started
321 struct timeval starttime;
324 int foregnd = 0; /* run in the foreground? */
329 /* File to write debug messages to */
330 #define LOG_FILE "/var/log/ilmid"
331 FILE *Log; /* File descriptor for log messages */
333 void set_reqid ( u_char *, int );
334 void Increment_DL ( int );
335 void Decrement_DL ( int );
337 static char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
338 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
341 * Write a syslog() style timestamp
343 * Write a syslog() style timestamp with month, day, time and hostname
354 write_timestamp(void)
359 clock = time ( (time_t)NULL );
360 tm = localtime ( &clock );
362 if ( Log && Debug_Level > 1 )
364 fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
365 Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
366 tm->tm_sec, hostname );
373 * Utility to pretty print buffer as hex dumps
376 * bp - buffer pointer
377 * len - length to pretty print
384 hexdump ( u_char *bp, int len )
389 * Print as 4 groups of four bytes. Each byte is separated
390 * by a space, each block of four is separated, and two blocks
391 * of eight are also separated.
393 for ( i = 0; i < len; i += 16 ) {
396 for ( j = 0; j < 4 && j + i < len; j++ )
398 fprintf ( Log, "%.2x ", *bp++ );
400 fprintf ( Log, " " );
401 for ( ; j < 8 && j + i < len; j++ )
403 fprintf ( Log, "%.2x ", *bp++ );
405 fprintf ( Log, " " );
408 for ( ; j < 12 && j + i < len; j++ )
410 fprintf ( Log, "%.2x ", *bp++ );
412 fprintf ( Log, " " );
413 for ( ; j < 16 && j + i < len; j++ )
415 fprintf ( Log, "%.2x ", *bp++ );
417 fprintf ( Log, "\n" );
427 * Get lengths from PDU encodings
429 * Lengths are sometimes encoded as a single byte if the length
430 * is less the 127 but are more commonly encoded as one byte with
431 * the high bit set and the lower seven bits indicating the nuber
432 * of bytes which make up the length value. Trailing data is (to my
433 * knowledge) not 7-bit encoded.
436 * bufp - pointer to buffer pointer
437 * plen - pointer to PDU length or NULL if not a concern
440 * bufp - updated buffer pointer
441 * plen - (possibly) adjusted pdu length
442 * <len> - decoded length
446 asn_get_pdu_len ( u_char **bufp, int *plen )
456 for ( i = 0; i < (b & ~0x80); i++ ) {
457 len = len * 256 + *bp++;
469 * Get an 7-bit encoded value.
471 * Get a value which is represented using a 7-bit encoding. The last
472 * byte in the stream has the high-bit clear.
475 * bufp - pointer to the buffer pointer
476 * len - pointer to the buffer length
479 * bufp - updated buffer pointer
480 * len - updated buffer length
481 * <val> - value encoding represented
485 asn_get_encoded ( bufp, len )
494 * Keep going while high bit is set
498 * Each byte can represent 7 bits
500 val = ( val << 7 ) + ( *bp & ~0x80 );
502 } while ( *bp++ & 0x80 );
504 *bufp = bp; /* update buffer pointer */
505 *len = l; /* update buffer length */
511 * Get a BER encoded integer
513 * Intergers are encoded as one byte length followed by <length> data bytes
516 * bufp - pointer to the buffer pointer
517 * plen - pointer to PDU length or NULL if not a concern
520 * bufp - updated buffer pointer
521 * plen - (possibly) updated PDU length
522 * <val> - value of encoded integer
526 asn_get_int ( bufp, plen )
538 for ( i = 0; i < len; i++ ) {
539 v = (v * 256) + *bp++;
548 * Set a BER encoded integer
551 * bufp - pointer to buffer pointer where we are to set int in
552 * val - integer value to set
556 * <bufp> - updated buffer pointer
560 asn_set_int ( bufp, val )
568 int len = sizeof(int);
572 /* Check for special case where val == 0 */
582 while ( u.c[i] == 0 && i++ < sizeof(int) )
585 if ( u.c[i] > 0x7f ) {
591 UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
599 * Utility to print a object identifier
602 * objid - pointer to objid representation
609 print_objid ( objid )
615 * First oid coded as 40 * X + Y
619 fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
620 objid->oid[1] % 40 );
622 for ( i = 2; i <= objid->oid[0]; i++ )
624 fprintf ( Log, ".%d", objid->oid[i] );
626 fprintf ( Log, "\n" );
632 * Get Object Identifier
635 * bufp - pointer to buffer pointer
636 * objid - pointer to objid buffer
637 * plen - pointer to PDU length or NULL of not a concern
640 * bufp - updated buffer pointer
641 * objid - internal representation of encoded objid
642 * plen - (possibly) adjusted PDU length
646 asn_get_objid ( bufp, objid, plen )
653 int *ip = (int *)objid + 1; /* First byte will contain length */
660 *ip++ = asn_get_encoded ( &bp, &len );
665 objid->oid[0] = oidlen;
672 * Put OBJID - assumes elements <= 16383 for two byte coding
676 asn_put_objid ( bufp, objid )
686 *bp++ = objid->oid[0];
688 for ( i = 1; i <= objid->oid[0]; i++ ) {
689 u_int c = objid->oid[i];
692 *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
694 c &= 0x7f; /* XXX - assumption of two bytes */
709 * Octet strings are encoded as a 7-bit encoded length followed by <len>
713 * bufp - pointer to buffer pointer
714 * octet - pointer to octet buffer
715 * plen - pointer to PDU length
718 * bufp - updated buffer pointer
719 * octet - encoded Octet String
720 * plen - (possibly) adjusted PDU length
724 asn_get_octet ( bufp, octet, plen )
734 * &i is really a dummy value here as we don't keep track
735 * of the ongoing buffer length
737 len = asn_get_encoded ( &bp, &i, plen );
739 for ( i = 0; i < len; i++ ) {
752 * Utility to print SNMP PDU header information
755 * Hdr - pointer to internal SNMP header structure
770 "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x %s\n",
771 Hdr->pdulen, Hdr->version + 1, Hdr->community,
772 Hdr->pdutype, PDU_Types[Hdr->pdutype - PDU_TYPE_GET] );
774 if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
775 fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
776 Hdr->reqid, Hdr->error, Hdr->erridx );
783 fprintf ( Log, " Variable Type: %d", var->type );
784 if ( Var_Types[var->type] )
785 fprintf ( Log, " %s", Var_Types[var->type] );
786 fprintf ( Log, "\n\tObject: " );
787 print_objid ( &var->oid );
788 fprintf ( Log, "\tValue: " );
789 switch ( var->type ) {
791 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
794 fprintf ( Log, "NULL" );
797 fprintf ( Log, "[0x%x]", var->type );
800 fprintf ( Log, "\n" );
810 * Pull OID's from GET/SET message
813 * h - pointer to Snmp_Header
814 * bp - pointer to input PDU
831 if ( *bufp++ == ASN_SEQUENCE ) {
834 /* Create new Variable instance */
835 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
843 /* Set head iff NULL */
844 if ( h->head == NULL ) {
850 /* Get length of variable sequence */
851 sublen = asn_get_pdu_len ( &bufp, &len );
852 /* Should be OBJID type */
853 if ( *bufp++ != ASN_OBJID ) {
857 asn_get_objid ( &bufp, &var->oid, &len );
860 switch ( var->type ) {
862 var->var.ival = asn_get_int ( &bufp, &len );
869 asn_get_objid ( &bufp, &var->var.oval, &len );
872 asn_get_octet ( &bufp, var->var.sval, &len );
877 fprintf ( Log, "Unknown variable type: %d\n",
892 * Crack the SNMP header
894 * Pull the PDU length, SNMP version, SNMP community and PDU type.
895 * If present, also pull out the Request ID, Error status, and Error
899 * bufp - pointer to buffer pointer
902 * bufp - updated buffer pointer
903 * - generated SNMP header
907 asn_get_header ( bufp )
916 * Allocate memory to hold the SNMP header
918 if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
919 return ( (Snmp_Header *)NULL );
922 * Ensure that we wipe the slate clean
924 UM_ZERO ( h, sizeof ( Snmp_Header ) );
927 * PDU has to start as SEQUENCE OF
929 if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
930 return ( (Snmp_Header *)NULL );
933 * Get the length of remaining PDU data
935 h->pdulen = asn_get_pdu_len ( &bp, NULL );
938 * We expect to find an integer encoding Version-1
940 if ( *bp++ != ASN_INTEGER ) {
941 return ( (Snmp_Header *)NULL );
943 h->version = asn_get_int ( &bp, NULL );
946 * After the version, we need the community name
948 if ( *bp++ != ASN_OCTET ) {
949 return ( (Snmp_Header *)NULL );
951 asn_get_octet ( &bp, h->community, NULL );
954 * Single byte PDU type
959 * If this isn't a TRAP PDU, then look for the rest of the header
961 if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
963 (void) asn_get_pdu_len ( &bp, &dummy );
966 if ( *bp++ != ASN_INTEGER ) {
968 return ( (Snmp_Header *)NULL );
970 h->reqid = asn_get_int ( &bp, NULL );
973 if ( *bp++ != ASN_INTEGER ) {
975 return ( (Snmp_Header *)NULL );
977 h->error = asn_get_int ( &bp, NULL );
980 if ( *bp++ != ASN_INTEGER ) {
982 return ( (Snmp_Header *)NULL );
984 h->erridx = asn_get_int ( &bp, NULL );
987 if ( *bp++ != ASN_SEQUENCE ) {
989 return ( (Snmp_Header *)NULL );
991 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
992 h->varlen += ( len - 1 );
994 parse_oids ( h, &bp );
999 if ( Log && Debug_Level )
1007 * Compare two internal OID representations
1010 * oid1 - Internal Object Identifier
1011 * oid2 - Internal Object Identifier
1015 * 1 - Objid's don't match
1019 oid_cmp ( oid1, oid2 )
1028 if ( !(oid1->oid[0] == oid2->oid[0] ) )
1029 /* Different lengths */
1035 * value by value compare
1037 for ( i = 1; i <= len; i++ ) {
1038 if ( !(oid1->oid[i] == oid2->oid[i]) )
1039 /* values don't match */
1043 /* Objid's are identical */
1048 * Compare two internal OID representations
1051 * oid1 - Internal Object Identifier
1052 * oid2 - Internal Object Identifier
1053 * len - Length of OID to compare
1057 * 1 - Objid's don't match
1061 oid_ncmp ( oid1, oid2, len )
1068 * value by value compare
1070 for ( i = 1; i <= len; i++ ) {
1071 if ( !(oid1->oid[i] == oid2->oid[i]) )
1072 /* values don't match */
1076 /* Objid's are identical */
1081 * Find the index of a OBJID which matches this Variable instance
1084 * var - pointer to Variable instance
1087 * idx - index of matched Variable instance
1088 * -1 - no matching Variable found
1097 for ( i = 0; i < NUM_OIDS; i++ )
1098 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1107 * Return the time process has been running as a number of ticks
1119 struct timeval timenow;
1120 struct timeval timediff;
1122 (void) gettimeofday ( &timenow, NULL );
1124 * Adjust for subtraction
1127 timenow.tv_usec += 1000000;
1130 * Compute time since 'starttime'
1132 timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1133 timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1136 * Adjust difference timeval
1138 if ( timediff.tv_usec >= 1000000 ) {
1139 timediff.tv_usec -= 1000000;
1144 * Compute number of ticks
1146 return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1151 * Build a response PDU
1154 * hdr - pointer to PDU Header with completed Variable list
1161 build_pdu ( hdr, type )
1165 u_char *bp = Resp_Buf;
1176 * Clear out the reply
1178 UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1180 /* [0] is reserved for overall length */
1183 /* Start with SEQUENCE OF */
1184 *bp++ = ASN_SEQUENCE;
1185 /* - assume we can code length in two octets */
1190 *bp++ = ASN_INTEGER;
1191 asn_set_int ( &bp, hdr->version );
1192 /* Community name */
1194 *bp++ = strlen ( hdr->community );
1195 UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1196 bp += strlen ( hdr->community );
1200 /* Length of OID data - assume it'll fit in one octet */
1203 if ( type != PDU_TYPE_TRAP ) {
1205 *bp++ = ASN_INTEGER;
1206 asn_set_int ( &bp, hdr->reqid );
1208 * Check to see if all the vaiables were resolved - we do this
1209 * by looking for something which still has a ASN_NULL value.
1212 if ( type == PDU_TYPE_GETRESP ) {
1213 while ( var && erridx == 0 ) {
1214 if ( var->type != ASN_NULL ) {
1223 *bp++ = ASN_INTEGER;
1224 *bp++ = 0x01; /* length = 1 */
1226 *bp++ = SNMP_ERR_NOSUCHNAME;
1228 *bp++ = SNMP_ERR_NOERROR;
1230 *bp++ = ASN_INTEGER;
1231 *bp++ = 0x01; /* length = 1 */
1232 *bp++ = erridx; /* index - 0 if no error */
1234 /* type == PDU_TYPE_TRAP */
1236 /* Fill in ENTERPRISE OBJID */
1238 (void) asn_put_objid ( &bp, &hdr->enterprise );
1240 /* Fill in IP address */
1242 *bp++ = sizeof ( hdr->ipaddr );
1243 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1244 bp += sizeof(hdr->ipaddr);
1246 /* Fill in generic and specific trap types */
1247 *bp++ = ASN_INTEGER;
1248 asn_set_int ( &bp, hdr->generic_trap );
1249 *bp++ = ASN_INTEGER;
1250 asn_set_int ( &bp, hdr->specific_trap );
1252 /* Fill in time-stamp - assume 0 for now */
1253 *bp++ = ASN_TIMESTAMP;
1254 asn_set_int ( &bp, 0 );
1256 /* encoded length */
1257 traplen = ( bp - ppp - 1 );
1259 /* Continue with variable processing */
1263 *bp++ = ASN_SEQUENCE;
1265 /* - assume we can code length in two octets */
1271 /* Install Variables */
1279 *bp++ = ASN_SEQUENCE;
1281 /* - assume we can code length in two octets */
1288 len += asn_put_objid ( &bp, &var->oid );
1290 if ( erridx && varidx >= erridx ) {
1291 /* Code this variable as NULL */
1302 switch ( var->type ) {
1304 asn_set_int ( &bp, var->var.ival );
1305 len += ( *lpp + 1 );
1308 *bp++ = var->var.sval[0];
1310 UM_COPY ( (caddr_t)&var->var.sval[1],
1311 bp, var->var.sval[0] );
1312 len += var->var.sval[0];
1313 bp += var->var.sval[0];
1320 len += asn_put_objid ( &bp, &var->var.oval );
1327 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1332 asn_set_int ( &bp, var->var.ival );
1333 len += ( *lpp + 1 );
1340 /* Accumulate total Variable sequence length */
1341 varlen += (len + 4);
1343 /* Fill in length of this sequence */
1344 bpp[1] = len & 0xff;
1351 /* Fill in length of Variable sequence */
1352 vpp[1] = varlen & 0xff;
1353 vpp[0] = varlen >> 8;
1355 if ( type != PDU_TYPE_TRAP ) {
1356 /* Fill in length of data AFTER PDU type */
1357 *ppp = varlen + 12 + ppp[2]; /* + length of reqid */
1359 /* Fill in length of data AFTER PDU type */
1360 *ppp = varlen + traplen + 4; /* + length of initial sequence of */
1363 /* Fill in overall sequence length */
1364 pdulen = *ppp + 7 + strlen ( hdr->community );
1365 Resp_Buf[4] = pdulen & 0x7f;
1366 Resp_Buf[3] = pdulen >> 8;
1368 pdulen = bp - Resp_Buf - 1;
1370 Resp_Buf[0] = pdulen;
1372 hdr->pdutype = type;
1383 while ( hdr->head ) {
1384 var = hdr->head->next; /* Save next link */
1385 UM_FREE ( hdr->head ); /* Free current var */
1386 hdr->head = var; /* Set head to next link */
1389 UM_FREE ( hdr ); /* Free fixed portion */
1393 * Set Request ID in PDU
1396 * resp - Response PDU buffer
1397 * reqid - request id value
1400 * none - request id may/may not be set
1404 set_reqid ( resp, reqid )
1408 u_char *bp = (u_char *)&resp[18];
1417 * Replace the current Request ID with the supplied value
1419 UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1425 * Send a generic response packet
1428 * sd - socket to send the reply on
1429 * reqid - original request ID from GET PDU
1430 * resp - pointer to the response to send
1433 * none - response sent
1437 send_resp ( intf, Hdr, resp )
1444 if ( ilmi_fd[intf] > 0 ) {
1445 n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1446 if ( Log && Debug_Level > 1 ) {
1448 fprintf ( Log, "===== Sent %d of %d bytes (%d) =====\n", n, resp[0], ilmi_fd[intf] );
1449 print_header ( Hdr );
1450 if ( Debug_Level > 2 )
1451 hexdump ( (u_char *)&resp[1], resp[0] );
1460 * Build a COLD_START TRAP PDU
1469 hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1472 hdr->version = SNMP_VERSION_1 - 1;
1473 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1475 hdr->ipaddr = 0x0; /* 0.0.0.0 */
1476 hdr->generic_trap = TRAP_COLDSTART;
1477 hdr->specific_trap = 0;
1478 UM_COPY ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1481 hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1483 UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1485 var->type = ASN_NULL;
1491 * Build a Generic PDU Header
1495 build_generic_header()
1499 hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1502 hdr->version = SNMP_VERSION_1 - 1;
1503 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1509 * Initialize information on what physical adapters HARP knows about
1511 * Query the HARP subsystem about configuration and physical interface
1512 * information for any currently registered ATM adapters. Store the information
1513 * as arrays for easier indexing by SNMP port/index numbers.
1519 * none Information from HARP available
1525 struct air_cfg_rsp *cfg_info = NULL;
1526 struct air_int_rsp *intf_info = NULL;
1530 * Get configuration info - what's available with 'atm sh config'
1532 buf_len = get_cfg_info ( NULL, &cfg_info );
1534 * If error occurred, clear out everything
1536 if ( buf_len <= 0 ) {
1537 UM_ZERO ( Cfg, sizeof(Cfg) );
1538 UM_ZERO ( Intf, sizeof(Intf) );
1544 * Move to local storage
1546 UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1548 * Compute how many units information was returned for
1550 NUnits = buf_len / sizeof(struct air_cfg_rsp);
1552 UM_FREE ( cfg_info );
1555 * Get the per interface information
1557 buf_len = get_intf_info ( NULL, &intf_info );
1559 * If error occurred, clear out Intf info
1561 if ( buf_len <= 0 ) {
1562 UM_ZERO ( Intf, sizeof(Intf) );
1567 * Move to local storage
1569 UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1571 UM_FREE ( intf_info );
1579 * Open a new SNMP session for ILMI
1581 * Start by updating interface information, in particular, how many
1582 * interfaces are in the system. While we'll try to open sessons on
1583 * all interfaces, this deamon currently can only handle the first
1596 struct sockaddr_atm satm;
1597 struct t_atm_aal5 aal5;
1598 struct t_atm_traffic traffic;
1599 struct t_atm_bearer bearer;
1600 struct t_atm_qos qos;
1601 struct t_atm_app_name appname;
1603 char nifname[IFNAMSIZ];
1610 for ( unit = 0; unit < NUnits; unit++ ) {
1613 * ILMI only makes sense for UNI signalling protocols
1615 sig_proto = Intf[unit].anp_sig_proto;
1616 if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1617 sig_proto != ATM_SIG_UNI40 )
1620 if ( ilmi_fd[unit] == -1 ) {
1622 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1624 if ( ilmi_fd[unit] < 0 ) {
1630 * Set interface name. For now, we must have a netif to go on...
1632 if ( Intf[unit].anp_nif_cnt == 0 ) {
1633 if ( Debug_Level > 1 && Log ) {
1635 fprintf ( Log, "No nif on unit %d\n", unit );
1637 close ( ilmi_fd[unit] );
1641 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1642 optlen = sizeof ( nifname );
1643 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1644 T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1645 perror ( "setsockopt" );
1649 "Couldn't set interface name \"%s\"\n",
1652 if ( Debug_Level > 1 && Log ) {
1654 fprintf ( Log, "nifname: closing unit %d\n", unit );
1656 close ( ilmi_fd[unit] );
1662 * Set up destination SAP
1664 UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
1665 satm.satm_family = AF_ATM;
1666 #if (defined(BSD) && (BSD >= 199103))
1667 satm.satm_len = sizeof(satm);
1670 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1671 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1672 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1673 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1674 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1676 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1679 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1680 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1681 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1683 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1685 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1688 * Set up connection parameters
1690 aal5.forward_max_SDU_size = MAX_LEN;
1691 aal5.backward_max_SDU_size = MAX_LEN;
1692 aal5.SSCS_type = T_ATM_NULL;
1693 optlen = sizeof(aal5);
1694 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1695 (caddr_t) &aal5, optlen ) < 0 ) {
1696 perror ( "setsockopt(aal5)" );
1697 if ( Debug_Level > 1 && Log ) {
1699 fprintf ( Log, "aal5: closing unit %d\n", unit );
1701 close ( ilmi_fd[unit] );
1706 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1707 traffic.forward.PCR_all_traffic = 100000;
1708 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1709 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1710 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1711 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1712 traffic.forward.tagging = T_NO;
1713 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1714 traffic.backward.PCR_all_traffic = 100000;
1715 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1716 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1717 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1718 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1719 traffic.backward.tagging = T_NO;
1720 traffic.best_effort = T_YES;
1721 optlen = sizeof(traffic);
1722 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1723 (caddr_t)&traffic, optlen) < 0) {
1724 perror("setsockopt(traffic)");
1726 bearer.bearer_class = T_ATM_CLASS_X;
1727 bearer.traffic_type = T_ATM_NULL;
1728 bearer.timing_requirements = T_ATM_NULL;
1729 bearer.clipping_susceptibility = T_NO;
1730 bearer.connection_configuration = T_ATM_1_TO_1;
1731 optlen = sizeof(bearer);
1732 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1733 (caddr_t)&bearer, optlen) < 0) {
1734 perror("setsockopt(bearer)");
1737 qos.coding_standard = T_ATM_NETWORK_CODING;
1738 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1739 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1740 optlen = sizeof(qos);
1741 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1743 perror("setsockopt(qos)");
1746 subaddr.address_format = T_ATM_ABSENT;
1747 subaddr.address_length = 0;
1748 optlen = sizeof(subaddr);
1749 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1750 (caddr_t)&subaddr, optlen) < 0) {
1751 perror("setsockopt(dest_sub)");
1754 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1755 optlen = sizeof(appname);
1756 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1757 (caddr_t)&appname, optlen) < 0) {
1758 perror("setsockopt(appname)");
1762 * Now try to connect to destination
1764 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1765 sizeof(satm)) < 0 ) {
1766 perror ( "connect" );
1767 if ( Debug_Level > 1 && Log ) {
1769 fprintf ( Log, "connect: closing unit %d\n", unit );
1771 close ( ilmi_fd[unit] );
1776 if ( Debug_Level && Log ) {
1778 fprintf ( Log, "***** opened unit %d\n", unit );
1781 ilmi_state[unit] = ILMI_COLDSTART;
1792 * Get our local IP address for this interface
1795 * s - socket to find address for
1796 * aval - pointer to variable to store address in
1803 get_local_ip ( s, aval )
1807 char intf_name[IFNAMSIZ];
1808 int namelen = IFNAMSIZ;
1809 struct air_netif_rsp *net_info = NULL;
1810 struct sockaddr_in *sin;
1813 * Get physical interface name
1815 if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1816 (caddr_t) intf_name, &namelen ) )
1820 * Get network interface information for this physical interface
1822 get_netif_info ( intf_name, &net_info );
1823 if ( net_info == NULL )
1826 sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1831 UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1833 UM_FREE ( net_info );
1840 * Set local NSAP prefix and then reply with our full NSAP address.
1842 * Switch will send a SET message with the NSAP prefix after a coldStart.
1843 * We'll set that prefix into HARP and then send a SET message of our own
1844 * with our full interface NSAP address.
1847 * oid - objid from SET message
1848 * hdr - pointer to internal SNMP header
1849 * buf - pointer to SET buffer
1850 * s - socket to send messages on
1857 set_prefix ( oid, hdr, intf )
1862 struct atmsetreq asr;
1868 * Build IOCTL request to set prefix
1870 asr.asr_opcode = AIOCS_SET_PRF;
1871 strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1872 sizeof(asr.asr_prf_intf ) );
1874 * Pull prefix out of received Objid
1875 * save in set_prefix IOCTL and addressEntry table
1877 for ( i = 0; i < oid->oid[13]; i++ ) {
1878 asr.asr_prf_pref[i] = oid->oid[i + 14];
1882 * Pass new prefix to the HARP kernel
1884 fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1887 if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1888 if ( errno != EALREADY ) {
1889 syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1892 fprintf ( Log, "errno %d setting prefix\n",
1902 * Reload the cfg/intf info with newly set prefix
1906 aa = &Intf[intf].anp_addr;
1909 * Copy our NSAP into addressEntry table
1912 addressEntry[intf].oid[0] = 0;
1913 for ( i = 0; i < aa->address_length; i++ ) {
1914 addressEntry[intf].oid[0]++; /* Increment length */
1915 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1924 set_address ( hdr, intf )
1931 PDU_Header = build_generic_header();
1932 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
1933 var = PDU_Header->head;
1934 /* Copy generic addressEntry OBJID */
1935 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
1937 /* Set specific instance */
1938 i = var->oid.oid[0] + 1; /* Get length */
1939 var->oid.oid[i++] = 1;
1940 var->oid.oid[i++] = 1;
1941 var->oid.oid[i++] = 3;
1942 var->oid.oid[i++] = 0;
1944 /* Copy in address length */
1945 var->oid.oid[i++] = addressEntry[intf].oid[0];
1947 /* Copy in address */
1948 for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
1949 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
1950 var->oid.oid[0] = i - 1; /* Set new length */
1953 var->type = ASN_INTEGER;
1956 build_pdu ( PDU_Header, PDU_TYPE_SET );
1957 send_resp ( intf, PDU_Header, Resp_Buf );
1961 * Utility to strip off any leading path information from a filename
1964 * path pathname to strip
1967 * fname striped filename
1976 if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1985 * Increment Debug Level
1987 * Catches SIGUSR1 signal and increments value of Debug_Level
1990 * sig - signal number
1993 * none - Debug_Level incremented
1997 Increment_DL ( sig )
2001 if ( Debug_Level && Log == (FILE *)NULL ) {
2005 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2009 setbuf ( Log, NULL );
2011 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
2014 signal ( SIGUSR1, Increment_DL );
2019 * Decrement Debug Level
2021 * Catches SIGUSR2 signal and decrements value of Debug_Level
2024 * sig - signal number
2027 * none - Debug_Level decremented
2031 Decrement_DL ( sig )
2035 if ( Debug_Level <= 0 ) {
2039 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
2045 signal ( SIGUSR2, Decrement_DL );
2050 * Loop through GET variable list looking for matches
2054 process_get ( hdr, intf )
2063 idx = find_var ( var );
2066 var->type = ASN_OBJID;
2067 UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2068 (caddr_t)&var->var.oval,
2072 var->type = ASN_TIMESTAMP;
2073 var->var.ival = get_ticks();
2076 var->type = ASN_INTEGER;
2077 var->var.ival = UNITYPE_PRIVATE;
2080 var->type = ASN_INTEGER;
2081 switch ( Intf[intf].anp_sig_proto ) {
2083 var->var.ival = UNIVER_UNI30;
2086 var->var.ival = UNIVER_UNI31;
2089 var->var.ival = UNIVER_UNI40;
2092 var->var.ival = UNIVER_UNKNOWN;
2097 var->type = ASN_INTEGER;
2098 var->var.ival = DEVTYPE_USER;
2101 var->type = ASN_INTEGER;
2102 var->var.ival = 1024;
2105 var->type = ASN_INTEGER;
2106 var->var.ival = intf + 1;
2109 var->type = ASN_IPADDR;
2110 get_local_ip ( ilmi_fd[intf],
2116 var->type = ASN_INTEGER;
2117 var->var.ival = 0x30 + intf;
2120 var->type = ASN_OCTET;
2121 var->var.sval[0] = 6;
2122 UM_COPY ( (caddr_t)&Cfg[intf].acp_macaddr,
2123 (caddr_t)&var->var.sval[1], 6 );
2131 build_pdu ( hdr, PDU_TYPE_GETRESP );
2132 send_resp ( intf, hdr, Resp_Buf );
2137 * ILMI State Processing Loop
2161 * SunOS CC doesn't allow automatic aggregate initialization.
2162 * Initialize to zero which effects a poll operation.
2168 * Clear fd_set and initialize to check this interface
2171 for ( intf = 0; intf < MAX_UNITS; intf++ )
2172 if ( ilmi_fd[intf] > 0 ) {
2173 FD_SET ( ilmi_fd[intf], &rfd );
2174 maxfd = MAX ( maxfd, ilmi_fd[intf] );
2178 * Check for new interfaces
2182 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2184 * Do any pre-message state processing
2186 switch ( ilmi_state[intf] ) {
2187 case ILMI_COLDSTART:
2189 * Clear addressTable
2191 UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2194 * Start by sending a COLD_START trap. This should cause the
2195 * remote end to clear the associated prefix/address table(s).
2197 /* Build ColdStart TRAP header */
2198 ColdStart_Header = build_cold_start();
2199 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2200 send_resp ( intf, ColdStart_Header, Resp_Buf );
2203 * Start a timeout so that if the next state fails, we re-enter
2208 /* Enter new state */
2209 ilmi_state[intf] = ILMI_INIT;
2210 /* fall into ILMI_INIT */
2214 * After a COLD_START, we need to check that the remote end has
2215 * cleared any tables. Send a GET_NEXT request to check for this.
2216 * In the event that the table is not empty, or that no reply is
2217 * received, return to COLD_START state.
2219 PDU_Header = build_generic_header();
2220 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
2221 var = PDU_Header->head;
2222 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2224 var->type = ASN_NULL;
2228 * Send GETNEXT request looking for empty ATM Address Table
2230 PDU_Header->reqid = Req_ID++;
2231 build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2232 send_resp ( intf, PDU_Header, Resp_Buf );
2235 * Start a timeout while looking for SET message. If we don't receive
2236 * a SET, then go back to COLD_START state.
2242 /* Normal SNMP processing */
2250 count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2252 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2254 * Check for received messages
2256 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2258 n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2259 if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2260 ilmi_state[intf] = ILMI_COLDSTART;
2261 close ( ilmi_fd[intf] );
2264 if ( Log && Debug_Level > 1 ) fprintf ( Log, "***** state %d ***** read %d bytes from %d (%d) ***** %s *****\n",
2265 ilmi_state[intf], n, intf, ilmi_fd[intf], PDU_Types[buf[14] - 0xA0] ); {
2266 if ( Debug_Level > 2 )
2267 hexdump ( (caddr_t)&buf[1], n );
2269 bpp = (caddr_t)&buf[1];
2270 if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2273 /* What we do with this messages depends upon the state we're in */
2274 switch ( ilmi_state[intf] ) {
2275 case ILMI_COLDSTART:
2276 /* We should never be in this state here */
2280 /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2281 switch ( Hdr->pdutype ) {
2282 case PDU_TYPE_GETNEXT:
2284 * Should be because the remote side is attempting
2285 * to verify that our table is empty
2287 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2288 (caddr_t)&Objids[ADDRESS_OBJID],
2289 Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2290 if ( addressEntry[intf].oid[0] ) {
2292 /* Our table is not empty - return address */
2295 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2296 send_resp ( intf, Hdr, Resp_Buf );
2298 case PDU_TYPE_GETRESP:
2300 * This should be in response to our GETNEXT.
2301 * Check the OIDs and go onto ILMI_RUNNING if
2302 * the address table is empty. We can cheat and
2303 * not check sequence numbers because we only send
2304 * the one GETNEXT request and ILMI says we shouldn't
2305 * have interleaved sessions.
2308 * First look for empty table. If found, go to next state.
2310 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2311 ((Hdr->error == SNMP_ERR_NOERROR) &&
2312 ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2313 Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2314 ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2315 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2317 * Check to see if this matches our address
2318 * and if so, that it's a VALID entry.
2324 aa = &Intf[intf].anp_addr;
2325 if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2326 for ( l = 0; l < aa->address_length; l++ ) {
2327 if ( (int)((u_char *)(aa->address))[l] !=
2328 Hdr->head->oid.oid[14 + l] ) {
2334 if ( Hdr->head->var.ival == 1 ) {
2335 ilmi_state[intf] = ILMI_RUNNING;
2342 /* Look for SET_PREFIX Objid */
2343 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2344 (caddr_t)&Objids[SETPFX_OBJID],
2345 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2346 set_prefix ( &Hdr->head->oid, Hdr, intf );
2347 /* Reply to SET before sending our ADDRESS */
2348 build_pdu(Hdr, PDU_TYPE_GETRESP);
2349 send_resp( intf, Hdr, Resp_Buf );
2350 set_address ( Hdr, intf );
2352 build_pdu(Hdr, PDU_TYPE_GETRESP);
2353 send_resp( intf, Hdr, Resp_Buf );
2357 /* Remote side wants us to start fresh */
2369 /* We'll take anything here */
2370 switch ( Hdr->pdutype ) {
2372 process_get ( Hdr, intf );
2374 case PDU_TYPE_GETRESP:
2375 /* Ignore GETRESPs */
2378 case PDU_TYPE_GETNEXT:
2379 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2380 send_resp ( intf, Hdr, Resp_Buf );
2383 /* Look for SET_PREFIX Objid */
2384 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2385 (caddr_t)&Objids[SETPFX_OBJID],
2386 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2387 set_prefix ( &Hdr->head->oid, Hdr, intf );
2388 /* Reply to SET before sending our ADDRESS */
2389 build_pdu(Hdr, PDU_TYPE_GETRESP);
2390 send_resp( intf, Hdr, Resp_Buf );
2391 set_address ( Hdr, intf );
2393 build_pdu(Hdr, PDU_TYPE_GETRESP);
2394 send_resp( intf, Hdr, Resp_Buf );
2408 } /* if received message */
2409 } /* for each interface */
2410 } /* for ever loop */
2421 int Reset = 0; /* Should we send a coldStart and exit? */
2424 * What are we running as? (argv[0])
2426 progname = strdup ( (char *)basename ( argv[0] ) );
2430 gethostname ( hostname, sizeof ( hostname ) );
2433 * Ilmid needs to run as root to set prefix
2435 if ( getuid() != 0 ) {
2436 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2443 while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2446 Debug_Level = atoi ( optarg );
2455 fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2463 * If we're not doing debugging, run in the background
2465 if ( foregnd == 0 ) {
2466 if ( daemon ( 0, 0 ) )
2467 err ( 1, "Can't fork" );
2469 ; /* setbuf ( stdout, NULL ); */
2471 signal ( SIGUSR1, Increment_DL );
2472 signal ( SIGUSR2, Decrement_DL );
2477 if ( Debug_Level ) {
2481 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2486 setbuf ( Log, NULL );
2489 * Get our startup time
2491 (void) gettimeofday ( &starttime, NULL );
2493 starttime.tv_usec += 1000000;
2495 /* Randomize starting request ID */
2496 Req_ID = starttime.tv_sec;
2499 * Reset all the interface descriptors
2501 for ( i = 0; i < MAX_UNITS; i++ ) {
2505 * Try to open all the interfaces
2510 * If we're just sending a coldStart end exiting...
2513 for ( i = 0; i < MAX_UNITS; i++ )
2514 if ( ilmi_fd[i] >= 0 ) {
2515 /* Build ColdStart TRAP header */
2516 ColdStart_Header = build_cold_start();
2517 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2518 send_resp ( i, ColdStart_Header, Resp_Buf );
2519 if ( Debug_Level > 1 && Log ) {
2521 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2524 close ( ilmi_fd[i] );