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.3 2003/08/08 04:18:37 dillon 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 __P ( ( u_char *, int ) );
334 void Increment_DL __P ( ( int ) );
335 void Decrement_DL __P ( ( 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
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
391 * Print as 4 groups of four bytes. Each byte is separated
392 * by a space, each block of four is separated, and two blocks
393 * of eight are also separated.
395 for ( i = 0; i < len; i += 16 ) {
398 for ( j = 0; j < 4 && j + i < len; j++ )
400 fprintf ( Log, "%.2x ", *bp++ );
402 fprintf ( Log, " " );
403 for ( ; j < 8 && j + i < len; j++ )
405 fprintf ( Log, "%.2x ", *bp++ );
407 fprintf ( Log, " " );
410 for ( ; j < 12 && j + i < len; j++ )
412 fprintf ( Log, "%.2x ", *bp++ );
414 fprintf ( Log, " " );
415 for ( ; j < 16 && j + i < len; j++ )
417 fprintf ( Log, "%.2x ", *bp++ );
419 fprintf ( Log, "\n" );
429 * Get lengths from PDU encodings
431 * Lengths are sometimes encoded as a single byte if the length
432 * is less the 127 but are more commonly encoded as one byte with
433 * the high bit set and the lower seven bits indicating the nuber
434 * of bytes which make up the length value. Trailing data is (to my
435 * knowledge) not 7-bit encoded.
438 * bufp - pointer to buffer pointer
439 * plen - pointer to PDU length or NULL if not a concern
442 * bufp - updated buffer pointer
443 * plen - (possibly) adjusted pdu length
444 * <len> - decoded length
448 asn_get_pdu_len ( bufp, plen )
460 for ( i = 0; i < (b & ~0x80); i++ ) {
461 len = len * 256 + *bp++;
473 * Get an 7-bit encoded value.
475 * Get a value which is represented using a 7-bit encoding. The last
476 * byte in the stream has the high-bit clear.
479 * bufp - pointer to the buffer pointer
480 * len - pointer to the buffer length
483 * bufp - updated buffer pointer
484 * len - updated buffer length
485 * <val> - value encoding represented
489 asn_get_encoded ( bufp, len )
498 * Keep going while high bit is set
502 * Each byte can represent 7 bits
504 val = ( val << 7 ) + ( *bp & ~0x80 );
506 } while ( *bp++ & 0x80 );
508 *bufp = bp; /* update buffer pointer */
509 *len = l; /* update buffer length */
515 * Get a BER encoded integer
517 * Intergers are encoded as one byte length followed by <length> data bytes
520 * bufp - pointer to the buffer pointer
521 * plen - pointer to PDU length or NULL if not a concern
524 * bufp - updated buffer pointer
525 * plen - (possibly) updated PDU length
526 * <val> - value of encoded integer
530 asn_get_int ( bufp, plen )
542 for ( i = 0; i < len; i++ ) {
543 v = (v * 256) + *bp++;
552 * Set a BER encoded integer
555 * bufp - pointer to buffer pointer where we are to set int in
556 * val - integer value to set
560 * <bufp> - updated buffer pointer
564 asn_set_int ( bufp, val )
572 int len = sizeof(int);
576 /* Check for special case where val == 0 */
586 while ( u.c[i] == 0 && i++ < sizeof(int) )
589 if ( u.c[i] > 0x7f ) {
595 UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
603 * Utility to print a object identifier
606 * objid - pointer to objid representation
613 print_objid ( objid )
619 * First oid coded as 40 * X + Y
623 fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
624 objid->oid[1] % 40 );
626 for ( i = 2; i <= objid->oid[0]; i++ )
628 fprintf ( Log, ".%d", objid->oid[i] );
630 fprintf ( Log, "\n" );
636 * Get Object Identifier
639 * bufp - pointer to buffer pointer
640 * objid - pointer to objid buffer
641 * plen - pointer to PDU length or NULL of not a concern
644 * bufp - updated buffer pointer
645 * objid - internal representation of encoded objid
646 * plen - (possibly) adjusted PDU length
650 asn_get_objid ( bufp, objid, plen )
657 int *ip = (int *)objid + 1; /* First byte will contain length */
664 *ip++ = asn_get_encoded ( &bp, &len );
669 objid->oid[0] = oidlen;
676 * Put OBJID - assumes elements <= 16383 for two byte coding
680 asn_put_objid ( bufp, objid )
690 *bp++ = objid->oid[0];
692 for ( i = 1; i <= objid->oid[0]; i++ ) {
693 u_int c = objid->oid[i];
696 *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
698 c &= 0x7f; /* XXX - assumption of two bytes */
713 * Octet strings are encoded as a 7-bit encoded length followed by <len>
717 * bufp - pointer to buffer pointer
718 * octet - pointer to octet buffer
719 * plen - pointer to PDU length
722 * bufp - updated buffer pointer
723 * octet - encoded Octet String
724 * plen - (possibly) adjusted PDU length
728 asn_get_octet ( bufp, octet, plen )
738 * &i is really a dummy value here as we don't keep track
739 * of the ongoing buffer length
741 len = asn_get_encoded ( &bp, &i, plen );
743 for ( i = 0; i < len; i++ ) {
756 * Utility to print SNMP PDU header information
759 * Hdr - pointer to internal SNMP header structure
774 "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x %s\n",
775 Hdr->pdulen, Hdr->version + 1, Hdr->community,
776 Hdr->pdutype, PDU_Types[Hdr->pdutype - PDU_TYPE_GET] );
778 if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
779 fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
780 Hdr->reqid, Hdr->error, Hdr->erridx );
787 fprintf ( Log, " Variable Type: %d", var->type );
788 if ( Var_Types[var->type] )
789 fprintf ( Log, " %s", Var_Types[var->type] );
790 fprintf ( Log, "\n\tObject: " );
791 print_objid ( &var->oid );
792 fprintf ( Log, "\tValue: " );
793 switch ( var->type ) {
795 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
798 fprintf ( Log, "NULL" );
801 fprintf ( Log, "[0x%x]", var->type );
804 fprintf ( Log, "\n" );
814 * Pull OID's from GET/SET message
817 * h - pointer to Snmp_Header
818 * bp - pointer to input PDU
835 if ( *bufp++ == ASN_SEQUENCE ) {
838 /* Create new Variable instance */
839 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
847 /* Set head iff NULL */
848 if ( h->head == NULL ) {
854 /* Get length of variable sequence */
855 sublen = asn_get_pdu_len ( &bufp, &len );
856 /* Should be OBJID type */
857 if ( *bufp++ != ASN_OBJID ) {
861 asn_get_objid ( &bufp, &var->oid, &len );
864 switch ( var->type ) {
866 var->var.ival = asn_get_int ( &bufp, &len );
873 asn_get_objid ( &bufp, &var->var.oval, &len );
876 asn_get_octet ( &bufp, var->var.sval, &len );
881 fprintf ( Log, "Unknown variable type: %d\n",
896 * Crack the SNMP header
898 * Pull the PDU length, SNMP version, SNMP community and PDU type.
899 * If present, also pull out the Request ID, Error status, and Error
903 * bufp - pointer to buffer pointer
906 * bufp - updated buffer pointer
907 * - generated SNMP header
911 asn_get_header ( bufp )
920 * Allocate memory to hold the SNMP header
922 if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
923 return ( (Snmp_Header *)NULL );
926 * Ensure that we wipe the slate clean
928 UM_ZERO ( h, sizeof ( Snmp_Header ) );
931 * PDU has to start as SEQUENCE OF
933 if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
934 return ( (Snmp_Header *)NULL );
937 * Get the length of remaining PDU data
939 h->pdulen = asn_get_pdu_len ( &bp, NULL );
942 * We expect to find an integer encoding Version-1
944 if ( *bp++ != ASN_INTEGER ) {
945 return ( (Snmp_Header *)NULL );
947 h->version = asn_get_int ( &bp, NULL );
950 * After the version, we need the community name
952 if ( *bp++ != ASN_OCTET ) {
953 return ( (Snmp_Header *)NULL );
955 asn_get_octet ( &bp, h->community, NULL );
958 * Single byte PDU type
963 * If this isn't a TRAP PDU, then look for the rest of the header
965 if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
967 (void) asn_get_pdu_len ( &bp, &dummy );
970 if ( *bp++ != ASN_INTEGER ) {
972 return ( (Snmp_Header *)NULL );
974 h->reqid = asn_get_int ( &bp, NULL );
977 if ( *bp++ != ASN_INTEGER ) {
979 return ( (Snmp_Header *)NULL );
981 h->error = asn_get_int ( &bp, NULL );
984 if ( *bp++ != ASN_INTEGER ) {
986 return ( (Snmp_Header *)NULL );
988 h->erridx = asn_get_int ( &bp, NULL );
991 if ( *bp++ != ASN_SEQUENCE ) {
993 return ( (Snmp_Header *)NULL );
995 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
996 h->varlen += ( len - 1 );
998 parse_oids ( h, &bp );
1003 if ( Log && Debug_Level )
1011 * Compare two internal OID representations
1014 * oid1 - Internal Object Identifier
1015 * oid2 - Internal Object Identifier
1019 * 1 - Objid's don't match
1023 oid_cmp ( oid1, oid2 )
1032 if ( !(oid1->oid[0] == oid2->oid[0] ) )
1033 /* Different lengths */
1039 * value by value compare
1041 for ( i = 1; i <= len; i++ ) {
1042 if ( !(oid1->oid[i] == oid2->oid[i]) )
1043 /* values don't match */
1047 /* Objid's are identical */
1052 * Compare two internal OID representations
1055 * oid1 - Internal Object Identifier
1056 * oid2 - Internal Object Identifier
1057 * len - Length of OID to compare
1061 * 1 - Objid's don't match
1065 oid_ncmp ( oid1, oid2, len )
1072 * value by value compare
1074 for ( i = 1; i <= len; i++ ) {
1075 if ( !(oid1->oid[i] == oid2->oid[i]) )
1076 /* values don't match */
1080 /* Objid's are identical */
1085 * Find the index of a OBJID which matches this Variable instance
1088 * var - pointer to Variable instance
1091 * idx - index of matched Variable instance
1092 * -1 - no matching Variable found
1101 for ( i = 0; i < NUM_OIDS; i++ )
1102 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1111 * Return the time process has been running as a number of ticks
1123 struct timeval timenow;
1124 struct timeval timediff;
1126 (void) gettimeofday ( &timenow, NULL );
1128 * Adjust for subtraction
1131 timenow.tv_usec += 1000000;
1134 * Compute time since 'starttime'
1136 timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1137 timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1140 * Adjust difference timeval
1142 if ( timediff.tv_usec >= 1000000 ) {
1143 timediff.tv_usec -= 1000000;
1148 * Compute number of ticks
1150 return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1155 * Build a response PDU
1158 * hdr - pointer to PDU Header with completed Variable list
1165 build_pdu ( hdr, type )
1169 u_char *bp = Resp_Buf;
1180 * Clear out the reply
1182 UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1184 /* [0] is reserved for overall length */
1187 /* Start with SEQUENCE OF */
1188 *bp++ = ASN_SEQUENCE;
1189 /* - assume we can code length in two octets */
1194 *bp++ = ASN_INTEGER;
1195 asn_set_int ( &bp, hdr->version );
1196 /* Community name */
1198 *bp++ = strlen ( hdr->community );
1199 UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1200 bp += strlen ( hdr->community );
1204 /* Length of OID data - assume it'll fit in one octet */
1207 if ( type != PDU_TYPE_TRAP ) {
1209 *bp++ = ASN_INTEGER;
1210 asn_set_int ( &bp, hdr->reqid );
1212 * Check to see if all the vaiables were resolved - we do this
1213 * by looking for something which still has a ASN_NULL value.
1216 if ( type == PDU_TYPE_GETRESP ) {
1217 while ( var && erridx == 0 ) {
1218 if ( var->type != ASN_NULL ) {
1227 *bp++ = ASN_INTEGER;
1228 *bp++ = 0x01; /* length = 1 */
1230 *bp++ = SNMP_ERR_NOSUCHNAME;
1232 *bp++ = SNMP_ERR_NOERROR;
1234 *bp++ = ASN_INTEGER;
1235 *bp++ = 0x01; /* length = 1 */
1236 *bp++ = erridx; /* index - 0 if no error */
1238 /* type == PDU_TYPE_TRAP */
1240 /* Fill in ENTERPRISE OBJID */
1242 (void) asn_put_objid ( &bp, &hdr->enterprise );
1244 /* Fill in IP address */
1246 *bp++ = sizeof ( hdr->ipaddr );
1247 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1248 bp += sizeof(hdr->ipaddr);
1250 /* Fill in generic and specific trap types */
1251 *bp++ = ASN_INTEGER;
1252 asn_set_int ( &bp, hdr->generic_trap );
1253 *bp++ = ASN_INTEGER;
1254 asn_set_int ( &bp, hdr->specific_trap );
1256 /* Fill in time-stamp - assume 0 for now */
1257 *bp++ = ASN_TIMESTAMP;
1258 asn_set_int ( &bp, 0 );
1260 /* encoded length */
1261 traplen = ( bp - ppp - 1 );
1263 /* Continue with variable processing */
1267 *bp++ = ASN_SEQUENCE;
1269 /* - assume we can code length in two octets */
1275 /* Install Variables */
1283 *bp++ = ASN_SEQUENCE;
1285 /* - assume we can code length in two octets */
1292 len += asn_put_objid ( &bp, &var->oid );
1294 if ( erridx && varidx >= erridx ) {
1295 /* Code this variable as NULL */
1306 switch ( var->type ) {
1308 asn_set_int ( &bp, var->var.ival );
1309 len += ( *lpp + 1 );
1312 *bp++ = var->var.sval[0];
1314 UM_COPY ( (caddr_t)&var->var.sval[1],
1315 bp, var->var.sval[0] );
1316 len += var->var.sval[0];
1317 bp += var->var.sval[0];
1324 len += asn_put_objid ( &bp, &var->var.oval );
1331 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1336 asn_set_int ( &bp, var->var.ival );
1337 len += ( *lpp + 1 );
1344 /* Accumulate total Variable sequence length */
1345 varlen += (len + 4);
1347 /* Fill in length of this sequence */
1348 bpp[1] = len & 0xff;
1355 /* Fill in length of Variable sequence */
1356 vpp[1] = varlen & 0xff;
1357 vpp[0] = varlen >> 8;
1359 if ( type != PDU_TYPE_TRAP ) {
1360 /* Fill in length of data AFTER PDU type */
1361 *ppp = varlen + 12 + ppp[2]; /* + length of reqid */
1363 /* Fill in length of data AFTER PDU type */
1364 *ppp = varlen + traplen + 4; /* + length of initial sequence of */
1367 /* Fill in overall sequence length */
1368 pdulen = *ppp + 7 + strlen ( hdr->community );
1369 Resp_Buf[4] = pdulen & 0x7f;
1370 Resp_Buf[3] = pdulen >> 8;
1372 pdulen = bp - Resp_Buf - 1;
1374 Resp_Buf[0] = pdulen;
1376 hdr->pdutype = type;
1387 while ( hdr->head ) {
1388 var = hdr->head->next; /* Save next link */
1389 UM_FREE ( hdr->head ); /* Free current var */
1390 hdr->head = var; /* Set head to next link */
1393 UM_FREE ( hdr ); /* Free fixed portion */
1397 * Set Request ID in PDU
1400 * resp - Response PDU buffer
1401 * reqid - request id value
1404 * none - request id may/may not be set
1408 set_reqid ( resp, reqid )
1412 u_char *bp = (u_char *)&resp[18];
1421 * Replace the current Request ID with the supplied value
1423 UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1429 * Send a generic response packet
1432 * sd - socket to send the reply on
1433 * reqid - original request ID from GET PDU
1434 * resp - pointer to the response to send
1437 * none - response sent
1441 send_resp ( intf, Hdr, resp )
1448 if ( ilmi_fd[intf] > 0 ) {
1449 n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1450 if ( Log && Debug_Level > 1 ) {
1452 fprintf ( Log, "===== Sent %d of %d bytes (%d) =====\n", n, resp[0], ilmi_fd[intf] );
1453 print_header ( Hdr );
1454 if ( Debug_Level > 2 )
1455 hexdump ( (u_char *)&resp[1], resp[0] );
1464 * Build a COLD_START TRAP PDU
1473 hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1476 hdr->version = SNMP_VERSION_1 - 1;
1477 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1479 hdr->ipaddr = 0x0; /* 0.0.0.0 */
1480 hdr->generic_trap = TRAP_COLDSTART;
1481 hdr->specific_trap = 0;
1482 UM_COPY ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1485 hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1487 UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1489 var->type = ASN_NULL;
1495 * Build a Generic PDU Header
1499 build_generic_header()
1503 hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1506 hdr->version = SNMP_VERSION_1 - 1;
1507 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1513 * Initialize information on what physical adapters HARP knows about
1515 * Query the HARP subsystem about configuration and physical interface
1516 * information for any currently registered ATM adapters. Store the information
1517 * as arrays for easier indexing by SNMP port/index numbers.
1523 * none Information from HARP available
1529 struct air_cfg_rsp *cfg_info = NULL;
1530 struct air_int_rsp *intf_info = NULL;
1534 * Get configuration info - what's available with 'atm sh config'
1536 buf_len = get_cfg_info ( NULL, &cfg_info );
1538 * If error occurred, clear out everything
1540 if ( buf_len <= 0 ) {
1541 UM_ZERO ( Cfg, sizeof(Cfg) );
1542 UM_ZERO ( Intf, sizeof(Intf) );
1548 * Move to local storage
1550 UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1552 * Compute how many units information was returned for
1554 NUnits = buf_len / sizeof(struct air_cfg_rsp);
1556 UM_FREE ( cfg_info );
1559 * Get the per interface information
1561 buf_len = get_intf_info ( NULL, &intf_info );
1563 * If error occurred, clear out Intf info
1565 if ( buf_len <= 0 ) {
1566 UM_ZERO ( Intf, sizeof(Intf) );
1571 * Move to local storage
1573 UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1575 UM_FREE ( intf_info );
1583 * Open a new SNMP session for ILMI
1585 * Start by updating interface information, in particular, how many
1586 * interfaces are in the system. While we'll try to open sessons on
1587 * all interfaces, this deamon currently can only handle the first
1600 struct sockaddr_atm satm;
1601 struct t_atm_aal5 aal5;
1602 struct t_atm_traffic traffic;
1603 struct t_atm_bearer bearer;
1604 struct t_atm_qos qos;
1605 struct t_atm_app_name appname;
1607 char nifname[IFNAMSIZ];
1614 for ( unit = 0; unit < NUnits; unit++ ) {
1617 * ILMI only makes sense for UNI signalling protocols
1619 sig_proto = Intf[unit].anp_sig_proto;
1620 if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1621 sig_proto != ATM_SIG_UNI40 )
1624 if ( ilmi_fd[unit] == -1 ) {
1626 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1628 if ( ilmi_fd[unit] < 0 ) {
1634 * Set interface name. For now, we must have a netif to go on...
1636 if ( Intf[unit].anp_nif_cnt == 0 ) {
1637 if ( Debug_Level > 1 && Log ) {
1639 fprintf ( Log, "No nif on unit %d\n", unit );
1641 close ( ilmi_fd[unit] );
1645 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1646 optlen = sizeof ( nifname );
1647 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1648 T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1649 perror ( "setsockopt" );
1653 "Couldn't set interface name \"%s\"\n",
1656 if ( Debug_Level > 1 && Log ) {
1658 fprintf ( Log, "nifname: closing unit %d\n", unit );
1660 close ( ilmi_fd[unit] );
1666 * Set up destination SAP
1668 UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
1669 satm.satm_family = AF_ATM;
1670 #if (defined(BSD) && (BSD >= 199103))
1671 satm.satm_len = sizeof(satm);
1674 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1675 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1676 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1677 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1678 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1680 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1683 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1684 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1685 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1687 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1689 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1692 * Set up connection parameters
1694 aal5.forward_max_SDU_size = MAX_LEN;
1695 aal5.backward_max_SDU_size = MAX_LEN;
1696 aal5.SSCS_type = T_ATM_NULL;
1697 optlen = sizeof(aal5);
1698 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1699 (caddr_t) &aal5, optlen ) < 0 ) {
1700 perror ( "setsockopt(aal5)" );
1701 if ( Debug_Level > 1 && Log ) {
1703 fprintf ( Log, "aal5: closing unit %d\n", unit );
1705 close ( ilmi_fd[unit] );
1710 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1711 traffic.forward.PCR_all_traffic = 100000;
1712 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1713 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1714 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1715 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1716 traffic.forward.tagging = T_NO;
1717 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1718 traffic.backward.PCR_all_traffic = 100000;
1719 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1720 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1721 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1722 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1723 traffic.backward.tagging = T_NO;
1724 traffic.best_effort = T_YES;
1725 optlen = sizeof(traffic);
1726 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1727 (caddr_t)&traffic, optlen) < 0) {
1728 perror("setsockopt(traffic)");
1730 bearer.bearer_class = T_ATM_CLASS_X;
1731 bearer.traffic_type = T_ATM_NULL;
1732 bearer.timing_requirements = T_ATM_NULL;
1733 bearer.clipping_susceptibility = T_NO;
1734 bearer.connection_configuration = T_ATM_1_TO_1;
1735 optlen = sizeof(bearer);
1736 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1737 (caddr_t)&bearer, optlen) < 0) {
1738 perror("setsockopt(bearer)");
1741 qos.coding_standard = T_ATM_NETWORK_CODING;
1742 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1743 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1744 optlen = sizeof(qos);
1745 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1747 perror("setsockopt(qos)");
1750 subaddr.address_format = T_ATM_ABSENT;
1751 subaddr.address_length = 0;
1752 optlen = sizeof(subaddr);
1753 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1754 (caddr_t)&subaddr, optlen) < 0) {
1755 perror("setsockopt(dest_sub)");
1758 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1759 optlen = sizeof(appname);
1760 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1761 (caddr_t)&appname, optlen) < 0) {
1762 perror("setsockopt(appname)");
1766 * Now try to connect to destination
1768 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1769 sizeof(satm)) < 0 ) {
1770 perror ( "connect" );
1771 if ( Debug_Level > 1 && Log ) {
1773 fprintf ( Log, "connect: closing unit %d\n", unit );
1775 close ( ilmi_fd[unit] );
1780 if ( Debug_Level && Log ) {
1782 fprintf ( Log, "***** opened unit %d\n", unit );
1785 ilmi_state[unit] = ILMI_COLDSTART;
1796 * Get our local IP address for this interface
1799 * s - socket to find address for
1800 * aval - pointer to variable to store address in
1807 get_local_ip ( s, aval )
1811 char intf_name[IFNAMSIZ];
1812 int namelen = IFNAMSIZ;
1813 struct air_netif_rsp *net_info = NULL;
1814 struct sockaddr_in *sin;
1817 * Get physical interface name
1819 if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1820 (caddr_t) intf_name, &namelen ) )
1824 * Get network interface information for this physical interface
1826 get_netif_info ( intf_name, &net_info );
1827 if ( net_info == NULL )
1830 sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1835 UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1837 UM_FREE ( net_info );
1844 * Set local NSAP prefix and then reply with our full NSAP address.
1846 * Switch will send a SET message with the NSAP prefix after a coldStart.
1847 * We'll set that prefix into HARP and then send a SET message of our own
1848 * with our full interface NSAP address.
1851 * oid - objid from SET message
1852 * hdr - pointer to internal SNMP header
1853 * buf - pointer to SET buffer
1854 * s - socket to send messages on
1861 set_prefix ( oid, hdr, intf )
1866 struct atmsetreq asr;
1872 * Build IOCTL request to set prefix
1874 asr.asr_opcode = AIOCS_SET_PRF;
1875 strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1876 sizeof(asr.asr_prf_intf ) );
1878 * Pull prefix out of received Objid
1879 * save in set_prefix IOCTL and addressEntry table
1881 for ( i = 0; i < oid->oid[13]; i++ ) {
1882 asr.asr_prf_pref[i] = oid->oid[i + 14];
1886 * Pass new prefix to the HARP kernel
1888 fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1891 if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1892 if ( errno != EALREADY ) {
1893 syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1896 fprintf ( Log, "errno %d setting prefix\n",
1906 * Reload the cfg/intf info with newly set prefix
1910 aa = &Intf[intf].anp_addr;
1913 * Copy our NSAP into addressEntry table
1916 addressEntry[intf].oid[0] = 0;
1917 for ( i = 0; i < aa->address_length; i++ ) {
1918 addressEntry[intf].oid[0]++; /* Increment length */
1919 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1928 set_address ( hdr, intf )
1935 PDU_Header = build_generic_header();
1936 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
1937 var = PDU_Header->head;
1938 /* Copy generic addressEntry OBJID */
1939 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
1941 /* Set specific instance */
1942 i = var->oid.oid[0] + 1; /* Get length */
1943 var->oid.oid[i++] = 1;
1944 var->oid.oid[i++] = 1;
1945 var->oid.oid[i++] = 3;
1946 var->oid.oid[i++] = 0;
1948 /* Copy in address length */
1949 var->oid.oid[i++] = addressEntry[intf].oid[0];
1951 /* Copy in address */
1952 for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
1953 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
1954 var->oid.oid[0] = i - 1; /* Set new length */
1957 var->type = ASN_INTEGER;
1960 build_pdu ( PDU_Header, PDU_TYPE_SET );
1961 send_resp ( intf, PDU_Header, Resp_Buf );
1965 * Utility to strip off any leading path information from a filename
1968 * path pathname to strip
1971 * fname striped filename
1980 if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1989 * Increment Debug Level
1991 * Catches SIGUSR1 signal and increments value of Debug_Level
1994 * sig - signal number
1997 * none - Debug_Level incremented
2001 Increment_DL ( sig )
2005 if ( Debug_Level && Log == (FILE *)NULL ) {
2009 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2013 setbuf ( Log, NULL );
2015 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
2018 signal ( SIGUSR1, Increment_DL );
2023 * Decrement Debug Level
2025 * Catches SIGUSR2 signal and decrements value of Debug_Level
2028 * sig - signal number
2031 * none - Debug_Level decremented
2035 Decrement_DL ( sig )
2039 if ( Debug_Level <= 0 ) {
2043 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
2049 signal ( SIGUSR2, Decrement_DL );
2054 * Loop through GET variable list looking for matches
2058 process_get ( hdr, intf )
2067 idx = find_var ( var );
2070 var->type = ASN_OBJID;
2071 UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2072 (caddr_t)&var->var.oval,
2076 var->type = ASN_TIMESTAMP;
2077 var->var.ival = get_ticks();
2080 var->type = ASN_INTEGER;
2081 var->var.ival = UNITYPE_PRIVATE;
2084 var->type = ASN_INTEGER;
2085 switch ( Intf[intf].anp_sig_proto ) {
2087 var->var.ival = UNIVER_UNI30;
2090 var->var.ival = UNIVER_UNI31;
2093 var->var.ival = UNIVER_UNI40;
2096 var->var.ival = UNIVER_UNKNOWN;
2101 var->type = ASN_INTEGER;
2102 var->var.ival = DEVTYPE_USER;
2105 var->type = ASN_INTEGER;
2106 var->var.ival = 1024;
2109 var->type = ASN_INTEGER;
2110 var->var.ival = intf + 1;
2113 var->type = ASN_IPADDR;
2114 get_local_ip ( ilmi_fd[intf],
2120 var->type = ASN_INTEGER;
2121 var->var.ival = 0x30 + intf;
2124 var->type = ASN_OCTET;
2125 var->var.sval[0] = 6;
2126 UM_COPY ( (caddr_t)&Cfg[intf].acp_macaddr,
2127 (caddr_t)&var->var.sval[1], 6 );
2135 build_pdu ( hdr, PDU_TYPE_GETRESP );
2136 send_resp ( intf, hdr, Resp_Buf );
2141 * ILMI State Processing Loop
2165 * SunOS CC doesn't allow automatic aggregate initialization.
2166 * Initialize to zero which effects a poll operation.
2172 * Clear fd_set and initialize to check this interface
2175 for ( intf = 0; intf < MAX_UNITS; intf++ )
2176 if ( ilmi_fd[intf] > 0 ) {
2177 FD_SET ( ilmi_fd[intf], &rfd );
2178 maxfd = MAX ( maxfd, ilmi_fd[intf] );
2182 * Check for new interfaces
2186 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2188 * Do any pre-message state processing
2190 switch ( ilmi_state[intf] ) {
2191 case ILMI_COLDSTART:
2193 * Clear addressTable
2195 UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2198 * Start by sending a COLD_START trap. This should cause the
2199 * remote end to clear the associated prefix/address table(s).
2201 /* Build ColdStart TRAP header */
2202 ColdStart_Header = build_cold_start();
2203 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2204 send_resp ( intf, ColdStart_Header, Resp_Buf );
2207 * Start a timeout so that if the next state fails, we re-enter
2212 /* Enter new state */
2213 ilmi_state[intf] = ILMI_INIT;
2214 /* fall into ILMI_INIT */
2218 * After a COLD_START, we need to check that the remote end has
2219 * cleared any tables. Send a GET_NEXT request to check for this.
2220 * In the event that the table is not empty, or that no reply is
2221 * received, return to COLD_START state.
2223 PDU_Header = build_generic_header();
2224 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
2225 var = PDU_Header->head;
2226 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2228 var->type = ASN_NULL;
2232 * Send GETNEXT request looking for empty ATM Address Table
2234 PDU_Header->reqid = Req_ID++;
2235 build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2236 send_resp ( intf, PDU_Header, Resp_Buf );
2239 * Start a timeout while looking for SET message. If we don't receive
2240 * a SET, then go back to COLD_START state.
2246 /* Normal SNMP processing */
2254 count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2256 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2258 * Check for received messages
2260 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2262 n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2263 if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2264 ilmi_state[intf] = ILMI_COLDSTART;
2265 close ( ilmi_fd[intf] );
2268 if ( Log && Debug_Level > 1 ) fprintf ( Log, "***** state %d ***** read %d bytes from %d (%d) ***** %s *****\n",
2269 ilmi_state[intf], n, intf, ilmi_fd[intf], PDU_Types[buf[14] - 0xA0] ); {
2270 if ( Debug_Level > 2 )
2271 hexdump ( (caddr_t)&buf[1], n );
2273 bpp = (caddr_t)&buf[1];
2274 if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2277 /* What we do with this messages depends upon the state we're in */
2278 switch ( ilmi_state[intf] ) {
2279 case ILMI_COLDSTART:
2280 /* We should never be in this state here */
2284 /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2285 switch ( Hdr->pdutype ) {
2286 case PDU_TYPE_GETNEXT:
2288 * Should be because the remote side is attempting
2289 * to verify that our table is empty
2291 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2292 (caddr_t)&Objids[ADDRESS_OBJID],
2293 Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2294 if ( addressEntry[intf].oid[0] ) {
2296 /* Our table is not empty - return address */
2299 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2300 send_resp ( intf, Hdr, Resp_Buf );
2302 case PDU_TYPE_GETRESP:
2304 * This should be in response to our GETNEXT.
2305 * Check the OIDs and go onto ILMI_RUNNING if
2306 * the address table is empty. We can cheat and
2307 * not check sequence numbers because we only send
2308 * the one GETNEXT request and ILMI says we shouldn't
2309 * have interleaved sessions.
2312 * First look for empty table. If found, go to next state.
2314 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2315 ((Hdr->error == SNMP_ERR_NOERROR) &&
2316 ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2317 Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2318 ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2319 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2321 * Check to see if this matches our address
2322 * and if so, that it's a VALID entry.
2328 aa = &Intf[intf].anp_addr;
2329 if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2330 for ( l = 0; l < aa->address_length; l++ ) {
2331 if ( (int)((u_char *)(aa->address))[l] !=
2332 Hdr->head->oid.oid[14 + l] ) {
2338 if ( Hdr->head->var.ival == 1 ) {
2339 ilmi_state[intf] = ILMI_RUNNING;
2346 /* Look for SET_PREFIX Objid */
2347 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2348 (caddr_t)&Objids[SETPFX_OBJID],
2349 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2350 set_prefix ( &Hdr->head->oid, Hdr, intf );
2351 /* Reply to SET before sending our ADDRESS */
2352 build_pdu(Hdr, PDU_TYPE_GETRESP);
2353 send_resp( intf, Hdr, Resp_Buf );
2354 set_address ( Hdr, intf );
2356 build_pdu(Hdr, PDU_TYPE_GETRESP);
2357 send_resp( intf, Hdr, Resp_Buf );
2361 /* Remote side wants us to start fresh */
2373 /* We'll take anything here */
2374 switch ( Hdr->pdutype ) {
2376 process_get ( Hdr, intf );
2378 case PDU_TYPE_GETRESP:
2379 /* Ignore GETRESPs */
2382 case PDU_TYPE_GETNEXT:
2383 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2384 send_resp ( intf, Hdr, Resp_Buf );
2387 /* Look for SET_PREFIX Objid */
2388 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2389 (caddr_t)&Objids[SETPFX_OBJID],
2390 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2391 set_prefix ( &Hdr->head->oid, Hdr, intf );
2392 /* Reply to SET before sending our ADDRESS */
2393 build_pdu(Hdr, PDU_TYPE_GETRESP);
2394 send_resp( intf, Hdr, Resp_Buf );
2395 set_address ( Hdr, intf );
2397 build_pdu(Hdr, PDU_TYPE_GETRESP);
2398 send_resp( intf, Hdr, Resp_Buf );
2412 } /* if received message */
2413 } /* for each interface */
2414 } /* for ever loop */
2425 int Reset = 0; /* Should we send a coldStart and exit? */
2428 * What are we running as? (argv[0])
2430 progname = strdup ( (char *)basename ( argv[0] ) );
2434 gethostname ( hostname, sizeof ( hostname ) );
2437 * Ilmid needs to run as root to set prefix
2439 if ( getuid() != 0 ) {
2440 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2447 while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2450 Debug_Level = atoi ( optarg );
2459 fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2467 * If we're not doing debugging, run in the background
2469 if ( foregnd == 0 ) {
2470 if ( daemon ( 0, 0 ) )
2471 err ( 1, "Can't fork" );
2473 ; /* setbuf ( stdout, NULL ); */
2475 signal ( SIGUSR1, Increment_DL );
2476 signal ( SIGUSR2, Decrement_DL );
2481 if ( Debug_Level ) {
2485 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2490 setbuf ( Log, NULL );
2493 * Get our startup time
2495 (void) gettimeofday ( &starttime, NULL );
2497 starttime.tv_usec += 1000000;
2499 /* Randomize starting request ID */
2500 Req_ID = starttime.tv_sec;
2503 * Reset all the interface descriptors
2505 for ( i = 0; i < MAX_UNITS; i++ ) {
2509 * Try to open all the interfaces
2514 * If we're just sending a coldStart end exiting...
2517 for ( i = 0; i < MAX_UNITS; i++ )
2518 if ( ilmi_fd[i] >= 0 ) {
2519 /* Build ColdStart TRAP header */
2520 ColdStart_Header = build_cold_start();
2521 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2522 send_resp ( i, ColdStart_Header, Resp_Buf );
2523 if ( Debug_Level > 1 && Log ) {
2525 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2528 close ( ilmi_fd[i] );