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 $
33 * Implement very minimal ILMI address registration.
35 * Implement very crude and basic support for "cracking" and
36 * "encoding" SNMP PDU's to support ILMI prefix and NSAP address
37 * registration. Code is not robust nor is it meant to provide any
38 * "real" SNMP support. Much of the code expects predetermined values
39 * and will fail if anything else is found. Much of the "encoding" is
40 * done with pre-computed PDU's.
42 * See "The Simple Book", Marshall T. Rose, particularly chapter 5,
43 * for ASN and BER information.
47 #include <sys/param.h>
48 #include <sys/socket.h>
49 #include <sys/sockio.h>
51 #include <netinet/in.h>
52 #include <netatm/port.h>
53 #include <netatm/atm.h>
54 #include <netatm/atm_if.h>
55 #include <netatm/atm_sigmgr.h>
56 #include <netatm/atm_sap.h>
57 #include <netatm/atm_sys.h>
58 #include <netatm/atm_ioctl.h>
59 #include <dev/atm/hea/eni_stats.h>
60 #include <dev/atm/hfa/fore_aali.h>
61 #include <dev/atm/hfa/fore_slave.h>
62 #include <dev/atm/hfa/fore_stats.h>
79 * Define some ASN types
81 #define ASN_INTEGER 0x02
82 #define ASN_OCTET 0x04
84 #define ASN_OBJID 0x06
85 #define ASN_SEQUENCE 0x30
86 #define ASN_IPADDR 0x40
87 #define ASN_TIMESTAMP 0x43
89 static const char *Var_Types[] = { "", "", "ASN_INTEGER", "", "ASN_OCTET", "ASN_NULL", "ASN_OBJID" };
92 * Define SNMP PDU types
94 #define PDU_TYPE_GET 0xA0
95 #define PDU_TYPE_GETNEXT 0xA1
96 #define PDU_TYPE_GETRESP 0xA2
97 #define PDU_TYPE_SET 0xA3
98 #define PDU_TYPE_TRAP 0xA4
100 static const char *PDU_Types[] = { "GET REQUEST", "GETNEXT REQUEST", "GET RESPONSE", "SET REQUEST",
106 #define TRAP_COLDSTART 0
107 #define TRAP_WARMSTART 1
108 #define TRAP_LINKDOWN 2
109 #define TRAP_LINKUP 3
110 #define TRAP_AUTHFAIL 4
111 #define TRAP_EGPLOSS 5
112 #define TRAP_ENTERPRISE 6
115 * Define SNMP Version numbers
117 #define SNMP_VERSION_1 1
118 #define SNMP_VERSION_2 2
121 * SNMP Error-status values
123 #define SNMP_ERR_NOERROR 0
124 #define SNMP_ERR_TOOBIG 1
125 #define SNMP_ERR_NOSUCHNAME 2
126 #define SNMP_ERR_BADVALUE 3
127 #define SNMP_ERR_READONLY 4
128 #define SNMP_ERR_GENERR 5
131 * Max string length for Variable
138 #define VAR_UNKNOWN -1
141 * Define our internal representation of an OBJECT IDENTIFIER
146 typedef struct objid Objid;
149 * Define a Veriable classso that we can handle multiple GET/SET's
152 typedef struct variable Variable;
157 int ival; /* INTEGER/TIMESTAMP */
158 Objid oval; /* OBJID */
159 long aval; /* IPADDR */
160 char sval[STRLEN]; /* OCTET */
166 * Every SNMP PDU has the first four fields of this header. The only type
167 * which doesn't have the last three fields is the TRAP type.
175 /* GET/GETNEXT/GETRESP/SET */
190 typedef struct snmp_header Snmp_Header;
192 Snmp_Header *ColdStart_Header;
193 Snmp_Header *PDU_Header;
196 * Define some OBJET IDENTIFIERS that we'll try to reply to:
198 * sysUpTime: number of time ticks since this deamon came up
199 * netpfx_oid: network prefix table
200 * unitype: is this a PRIVATE or PUBLIC network link
201 * univer: which version of UNI are we running
202 * devtype: is this a USER or NODE ATM device
203 * setprefix: used when the switch wants to tell us its NSAP prefix
204 * foresiggrp: FORE specific Objid we see alot of (being connected to FORE
209 {{ 8, 43, 6, 1, 2, 1, 1, 2, 0 }},
210 #define UPTIME_OBJID 1
211 {{ 8, 43, 6, 1, 2, 1, 1, 3, 0 }},
213 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 1, 0 }},
215 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 2, 0 }},
216 #define LAYER_OBJID 4
217 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 1, 0 }},
218 #define MAXVCC_OBJID 5
219 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 3, 0 }},
220 #define UNITYPE_OBJID 6
221 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 8, 0 }},
222 #define UNIVER_OBJID 7
223 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 9, 0 }},
224 #define DEVTYPE_OBJID 8
225 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 10, 0 }},
226 #define ADDRESS_OBJID 9
227 {{ 8, 43, 6, 1, 4, 1, 353, 2, 6 }},
228 #define NETPFX_OBJID 10
229 {{ 9, 43, 6, 1, 4, 1, 353, 2, 7, 1 }},
231 {{ 7, 43, 6, 1, 4, 1, 9999, 1 }},
232 #define SETPFX_OBJID 12
233 {{ 12, 43, 6, 1, 4, 1, 353, 2, 7, 1, 1, 3, 0 }},
234 #define ENTERPRISE_OBJID 13
235 {{ 8, 43, 6, 1, 4, 1, 3, 1, 1 }},
236 #define ATMF_PORTID 14
237 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 4, 0 }},
238 #define ATMF_SYSID 15
239 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 8, 0 }},
242 #define NUM_OIDS (sizeof(Objids)/sizeof(Objid))
244 #define UNIVER_UNI20 1
245 #define UNIVER_UNI30 2
246 #define UNIVER_UNI31 3
247 #define UNIVER_UNI40 4
248 #define UNIVER_UNKNOWN 5
250 #define UNITYPE_PUBLIC 1
251 #define UNITYPE_PRIVATE 2
253 #define DEVTYPE_USER 1
254 #define DEVTYPE_NODE 2
257 * ILMI protocol states
260 ILMI_UNKNOWN, /* Uninitialized */
261 ILMI_COLDSTART, /* We need to send a COLD_START trap */
262 ILMI_INIT, /* Ensure that switch has reset */
263 ILMI_REG, /* Looking for SET message */
264 ILMI_RUNNING /* Normal processing */
268 * Our (incrementing) Request ID
273 * Temporary buffer for building response packets. Should help ensure
274 * that we aren't accidently overwriting some other memory.
276 u_char Resp_Buf[1024];
279 * Copy the reponse into a buffer we can modify without
280 * changing the original...
282 #define COPY_RESP(resp) \
283 UM_COPY ( (resp), Resp_Buf, (resp)[0] + 1 )
286 * TRAP generic trap types
288 const char *Traps[] = { "coldStart", "warmStart", "linkDown", "linkUp",
289 "authenticationFailure", "egpNeighborLoss",
290 "enterpriseSpecific" };
296 * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests
298 int ilmi_fd[MAX_UNITS + 1];
300 * enum ilmi_states for this unit
302 int ilmi_state[MAX_UNITS + 1];
304 * Local copy for HARP physical configuration information
306 struct air_cfg_rsp Cfg[MAX_UNITS + 1];
308 * Local copy for HARP interface configuration information
310 struct air_int_rsp Intf[MAX_UNITS + 1];
315 Objid addressEntry[MAX_UNITS + 1];
318 * When this daemon started
320 struct timeval starttime;
323 int foregnd = 0; /* run in the foreground? */
328 /* File to write debug messages to */
329 #define LOG_FILE "/var/log/ilmid"
330 FILE *Log; /* File descriptor for log messages */
332 static const char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
333 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
336 * Write a syslog() style timestamp
338 * Write a syslog() style timestamp with month, day, time and hostname
349 write_timestamp(void)
354 clk = time ( (time_t)NULL );
355 tm = localtime ( &clk );
357 if ( Log && Debug_Level > 1 )
359 fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
360 Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
361 tm->tm_sec, hostname );
368 * Utility to pretty print buffer as hex dumps
371 * bp - buffer pointer
372 * len - length to pretty print
379 hexdump ( u_char *bp, int len )
384 * Print as 4 groups of four bytes. Each byte is separated
385 * by a space, each block of four is separated, and two blocks
386 * of eight are also separated.
388 for ( i = 0; i < len; i += 16 ) {
391 for ( j = 0; j < 4 && j + i < len; j++ )
393 fprintf ( Log, "%.2x ", *bp++ );
395 fprintf ( Log, " " );
396 for ( ; j < 8 && j + i < len; j++ )
398 fprintf ( Log, "%.2x ", *bp++ );
400 fprintf ( Log, " " );
403 for ( ; j < 12 && j + i < len; j++ )
405 fprintf ( Log, "%.2x ", *bp++ );
407 fprintf ( Log, " " );
408 for ( ; j < 16 && j + i < len; j++ )
410 fprintf ( Log, "%.2x ", *bp++ );
412 fprintf ( Log, "\n" );
422 * Get lengths from PDU encodings
424 * Lengths are sometimes encoded as a single byte if the length
425 * is less the 127 but are more commonly encoded as one byte with
426 * the high bit set and the lower seven bits indicating the nuber
427 * of bytes which make up the length value. Trailing data is (to my
428 * knowledge) not 7-bit encoded.
431 * bufp - pointer to buffer pointer
432 * plen - pointer to PDU length or NULL if not a concern
435 * bufp - updated buffer pointer
436 * plen - (possibly) adjusted pdu length
437 * <len> - decoded length
441 asn_get_pdu_len ( u_char **bufp, int *plen )
451 for ( i = 0; i < (b & ~0x80); i++ ) {
452 len = len * 256 + *bp++;
464 * Get an 7-bit encoded value.
466 * Get a value which is represented using a 7-bit encoding. The last
467 * byte in the stream has the high-bit clear.
470 * bufp - pointer to the buffer pointer
471 * len - pointer to the buffer length
474 * bufp - updated buffer pointer
475 * len - updated buffer length
476 * <val> - value encoding represented
480 asn_get_encoded ( u_char **bufp, int *len )
487 * Keep going while high bit is set
491 * Each byte can represent 7 bits
493 val = ( val << 7 ) + ( *bp & ~0x80 );
495 } while ( *bp++ & 0x80 );
497 *bufp = bp; /* update buffer pointer */
498 *len = l; /* update buffer length */
504 * Get a BER encoded integer
506 * Intergers are encoded as one byte length followed by <length> data bytes
509 * bufp - pointer to the buffer pointer
510 * plen - pointer to PDU length or NULL if not a concern
513 * bufp - updated buffer pointer
514 * plen - (possibly) updated PDU length
515 * <val> - value of encoded integer
519 asn_get_int ( u_char **bufp, int *plen )
529 for ( i = 0; i < len; i++ ) {
530 v = (v * 256) + *bp++;
539 * Set a BER encoded integer
542 * bufp - pointer to buffer pointer where we are to set int in
543 * val - integer value to set
547 * <bufp> - updated buffer pointer
551 asn_set_int ( u_char **bufp, int val )
557 int len = sizeof(int);
561 /* Check for special case where val == 0 */
571 while ( u.c[i] == 0 && i++ < sizeof(int) )
574 if ( u.c[i] > 0x7f ) {
580 UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
588 * Utility to print a object identifier
591 * objid - pointer to objid representation
598 print_objid ( Objid *objid )
603 * First oid coded as 40 * X + Y
607 fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
608 objid->oid[1] % 40 );
610 for ( i = 2; i <= objid->oid[0]; i++ )
612 fprintf ( Log, ".%d", objid->oid[i] );
614 fprintf ( Log, "\n" );
620 * Get Object Identifier
623 * bufp - pointer to buffer pointer
624 * objid - pointer to objid buffer
625 * plen - pointer to PDU length or NULL of not a concern
628 * bufp - updated buffer pointer
629 * objid - internal representation of encoded objid
630 * plen - (possibly) adjusted PDU length
634 asn_get_objid ( u_char **bufp, Objid *objid, int *plen )
638 int *ip = (int *)objid + 1; /* First byte will contain length */
645 *ip++ = asn_get_encoded ( &bp, &len );
650 objid->oid[0] = oidlen;
657 * Put OBJID - assumes elements <= 16383 for two byte coding
661 asn_put_objid ( u_char **bufp, Objid *objid )
669 *bp++ = objid->oid[0];
671 for ( i = 1; i <= objid->oid[0]; i++ ) {
672 u_int c = objid->oid[i];
675 *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
677 c &= 0x7f; /* XXX - assumption of two bytes */
692 * Octet strings are encoded as a 7-bit encoded length followed by <len>
696 * bufp - pointer to buffer pointer
697 * octet - pointer to octet buffer
698 * plen - pointer to PDU length
701 * bufp - updated buffer pointer
702 * octet - encoded Octet String
703 * plen - (possibly) adjusted PDU length
707 asn_get_octet ( u_char **bufp, char *octet, int *plen )
714 * &i is really a dummy value here as we don't keep track
715 * of the ongoing buffer length
717 len = asn_get_encoded ( &bp, &i );
719 for ( i = 0; i < len; i++ ) {
732 * Utility to print SNMP PDU header information
735 * Hdr - pointer to internal SNMP header structure
742 print_header ( Snmp_Header *Hdr )
749 "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x %s\n",
750 Hdr->pdulen, Hdr->version + 1, Hdr->community,
751 Hdr->pdutype, PDU_Types[Hdr->pdutype - PDU_TYPE_GET] );
753 if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
754 fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
755 Hdr->reqid, Hdr->error, Hdr->erridx );
762 fprintf ( Log, " Variable Type: %d", var->type );
763 if ( Var_Types[var->type] )
764 fprintf ( Log, " %s", Var_Types[var->type] );
765 fprintf ( Log, "\n\tObject: " );
766 print_objid ( &var->oid );
767 fprintf ( Log, "\tValue: " );
768 switch ( var->type ) {
770 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
773 fprintf ( Log, "NULL" );
776 fprintf ( Log, "[0x%x]", var->type );
779 fprintf ( Log, "\n" );
789 * Pull OID's from GET/SET message
792 * h - pointer to Snmp_Header
793 * bp - pointer to input PDU
800 parse_oids ( Snmp_Header *h, u_char **bp )
808 if ( *bufp++ == ASN_SEQUENCE ) {
811 /* Create new Variable instance */
812 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
820 /* Set head iff NULL */
821 if ( h->head == NULL ) {
827 /* Get length of variable sequence */
828 sublen = asn_get_pdu_len ( &bufp, &len );
829 /* Should be OBJID type */
830 if ( *bufp++ != ASN_OBJID ) {
834 asn_get_objid ( &bufp, &var->oid, &len );
837 switch ( var->type ) {
839 var->var.ival = asn_get_int ( &bufp, &len );
846 asn_get_objid ( &bufp, &var->var.oval, &len );
849 asn_get_octet ( &bufp, var->var.sval, &len );
854 fprintf ( Log, "Unknown variable type: %d\n",
869 * Crack the SNMP header
871 * Pull the PDU length, SNMP version, SNMP community and PDU type.
872 * If present, also pull out the Request ID, Error status, and Error
876 * bufp - pointer to buffer pointer
879 * bufp - updated buffer pointer
880 * - generated SNMP header
884 asn_get_header ( u_char **bufp )
892 * Allocate memory to hold the SNMP header
894 if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
898 * Ensure that we wipe the slate clean
900 UM_ZERO ( h, sizeof ( Snmp_Header ) );
903 * PDU has to start as SEQUENCE OF
905 if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
909 * Get the length of remaining PDU data
911 h->pdulen = asn_get_pdu_len ( &bp, NULL );
914 * We expect to find an integer encoding Version-1
916 if ( *bp++ != ASN_INTEGER ) {
919 h->version = asn_get_int ( &bp, NULL );
922 * After the version, we need the community name
924 if ( *bp++ != ASN_OCTET ) {
927 asn_get_octet ( &bp, h->community, NULL );
930 * Single byte PDU type
935 * If this isn't a TRAP PDU, then look for the rest of the header
937 if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
939 asn_get_pdu_len ( &bp, &dummy );
942 if ( *bp++ != ASN_INTEGER ) {
946 h->reqid = asn_get_int ( &bp, NULL );
949 if ( *bp++ != ASN_INTEGER ) {
953 h->error = asn_get_int ( &bp, NULL );
956 if ( *bp++ != ASN_INTEGER ) {
960 h->erridx = asn_get_int ( &bp, NULL );
963 if ( *bp++ != ASN_SEQUENCE ) {
967 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
968 h->varlen += ( len - 1 );
970 parse_oids ( h, &bp );
975 if ( Log && Debug_Level )
983 * Compare two internal OID representations
986 * oid1 - Internal Object Identifier
987 * oid2 - Internal Object Identifier
991 * 1 - Objid's don't match
995 oid_cmp ( Objid *oid1, Objid *oid2 )
1003 if ( !(oid1->oid[0] == oid2->oid[0] ) )
1004 /* Different lengths */
1010 * value by value compare
1012 for ( i = 1; i <= len; i++ ) {
1013 if ( !(oid1->oid[i] == oid2->oid[i]) )
1014 /* values don't match */
1018 /* Objid's are identical */
1023 * Compare two internal OID representations
1026 * oid1 - Internal Object Identifier
1027 * oid2 - Internal Object Identifier
1028 * len - Length of OID to compare
1032 * 1 - Objid's don't match
1036 oid_ncmp ( Objid *oid1, Objid *oid2, int len )
1041 * value by value compare
1043 for ( i = 1; i <= len; i++ ) {
1044 if ( !(oid1->oid[i] == oid2->oid[i]) )
1045 /* values don't match */
1049 /* Objid's are identical */
1054 * Find the index of a OBJID which matches this Variable instance
1057 * var - pointer to Variable instance
1060 * idx - index of matched Variable instance
1061 * -1 - no matching Variable found
1065 find_var ( Variable *var )
1069 for ( i = 0; i < NUM_OIDS; i++ )
1070 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1079 * Return the time process has been running as a number of ticks
1091 struct timeval timenow;
1092 struct timeval timediff;
1094 gettimeofday ( &timenow, NULL );
1096 * Adjust for subtraction
1099 timenow.tv_usec += 1000000;
1102 * Compute time since 'starttime'
1104 timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1105 timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1108 * Adjust difference timeval
1110 if ( timediff.tv_usec >= 1000000 ) {
1111 timediff.tv_usec -= 1000000;
1116 * Compute number of ticks
1118 return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1123 * Build a response PDU
1126 * hdr - pointer to PDU Header with completed Variable list
1133 build_pdu ( Snmp_Header *hdr, int type )
1135 u_char *bp = Resp_Buf;
1146 * Clear out the reply
1148 UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1150 /* [0] is reserved for overall length */
1153 /* Start with SEQUENCE OF */
1154 *bp++ = ASN_SEQUENCE;
1155 /* - assume we can code length in two octets */
1160 *bp++ = ASN_INTEGER;
1161 asn_set_int ( &bp, hdr->version );
1162 /* Community name */
1164 *bp++ = strlen ( hdr->community );
1165 UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1166 bp += strlen ( hdr->community );
1170 /* Length of OID data - assume it'll fit in one octet */
1173 if ( type != PDU_TYPE_TRAP ) {
1175 *bp++ = ASN_INTEGER;
1176 asn_set_int ( &bp, hdr->reqid );
1178 * Check to see if all the vaiables were resolved - we do this
1179 * by looking for something which still has a ASN_NULL value.
1182 if ( type == PDU_TYPE_GETRESP ) {
1183 while ( var && erridx == 0 ) {
1184 if ( var->type != ASN_NULL ) {
1193 *bp++ = ASN_INTEGER;
1194 *bp++ = 0x01; /* length = 1 */
1196 *bp++ = SNMP_ERR_NOSUCHNAME;
1198 *bp++ = SNMP_ERR_NOERROR;
1200 *bp++ = ASN_INTEGER;
1201 *bp++ = 0x01; /* length = 1 */
1202 *bp++ = erridx; /* index - 0 if no error */
1204 /* type == PDU_TYPE_TRAP */
1206 /* Fill in ENTERPRISE OBJID */
1208 asn_put_objid ( &bp, &hdr->enterprise );
1210 /* Fill in IP address */
1212 *bp++ = sizeof ( hdr->ipaddr );
1213 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1214 bp += sizeof(hdr->ipaddr);
1216 /* Fill in generic and specific trap types */
1217 *bp++ = ASN_INTEGER;
1218 asn_set_int ( &bp, hdr->generic_trap );
1219 *bp++ = ASN_INTEGER;
1220 asn_set_int ( &bp, hdr->specific_trap );
1222 /* Fill in time-stamp - assume 0 for now */
1223 *bp++ = ASN_TIMESTAMP;
1224 asn_set_int ( &bp, 0 );
1226 /* encoded length */
1227 traplen = ( bp - ppp - 1 );
1229 /* Continue with variable processing */
1233 *bp++ = ASN_SEQUENCE;
1235 /* - assume we can code length in two octets */
1241 /* Install Variables */
1249 *bp++ = ASN_SEQUENCE;
1251 /* - assume we can code length in two octets */
1258 len += asn_put_objid ( &bp, &var->oid );
1260 if ( erridx && varidx >= erridx ) {
1261 /* Code this variable as NULL */
1272 switch ( var->type ) {
1274 asn_set_int ( &bp, var->var.ival );
1275 len += ( *lpp + 1 );
1278 *bp++ = var->var.sval[0];
1280 UM_COPY ( (caddr_t)&var->var.sval[1],
1281 bp, var->var.sval[0] );
1282 len += var->var.sval[0];
1283 bp += var->var.sval[0];
1290 len += asn_put_objid ( &bp, &var->var.oval );
1297 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1302 asn_set_int ( &bp, var->var.ival );
1303 len += ( *lpp + 1 );
1310 /* Accumulate total Variable sequence length */
1311 varlen += (len + 4);
1313 /* Fill in length of this sequence */
1314 bpp[1] = len & 0xff;
1321 /* Fill in length of Variable sequence */
1322 vpp[1] = varlen & 0xff;
1323 vpp[0] = varlen >> 8;
1325 if ( type != PDU_TYPE_TRAP ) {
1326 /* Fill in length of data AFTER PDU type */
1327 *ppp = varlen + 12 + ppp[2]; /* + length of reqid */
1329 /* Fill in length of data AFTER PDU type */
1330 *ppp = varlen + traplen + 4; /* + length of initial sequence of */
1333 /* Fill in overall sequence length */
1334 pdulen = *ppp + 7 + strlen ( hdr->community );
1335 Resp_Buf[4] = pdulen & 0x7f;
1336 Resp_Buf[3] = pdulen >> 8;
1338 pdulen = bp - Resp_Buf - 1;
1340 Resp_Buf[0] = pdulen;
1342 hdr->pdutype = type;
1348 free_pdu ( Snmp_Header *hdr )
1352 while ( hdr->head ) {
1353 var = hdr->head->next; /* Save next link */
1354 UM_FREE ( hdr->head ); /* Free current var */
1355 hdr->head = var; /* Set head to next link */
1358 UM_FREE ( hdr ); /* Free fixed portion */
1363 * Set Request ID in PDU
1366 * resp - Response PDU buffer
1367 * reqid - request id value
1370 * none - request id may/may not be set
1374 set_reqid ( u_char *resp, int reqid )
1376 u_char *bp = (u_char *)&resp[18];
1385 * Replace the current Request ID with the supplied value
1387 UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1394 * Send a generic response packet
1397 * sd - socket to send the reply on
1398 * reqid - original request ID from GET PDU
1399 * resp - pointer to the response to send
1402 * none - response sent
1406 send_resp ( int intf, Snmp_Header *Hdr, u_char *resp )
1410 if ( ilmi_fd[intf] > 0 ) {
1411 n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1412 if ( Log && Debug_Level > 1 ) {
1414 fprintf ( Log, "===== Sent %d of %d bytes (%d) =====\n", n, resp[0], ilmi_fd[intf] );
1415 print_header ( Hdr );
1416 if ( Debug_Level > 2 )
1417 hexdump ( (u_char *)&resp[1], resp[0] );
1426 * Build a COLD_START TRAP PDU
1429 static Snmp_Header *
1430 build_cold_start(void)
1435 hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1438 hdr->version = SNMP_VERSION_1 - 1;
1439 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1441 hdr->ipaddr = 0x0; /* 0.0.0.0 */
1442 hdr->generic_trap = TRAP_COLDSTART;
1443 hdr->specific_trap = 0;
1444 UM_COPY ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1447 hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1449 UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1451 var->type = ASN_NULL;
1457 * Build a Generic PDU Header
1460 static Snmp_Header *
1461 build_generic_header(void)
1465 hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1468 hdr->version = SNMP_VERSION_1 - 1;
1469 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1475 * Initialize information on what physical adapters HARP knows about
1477 * Query the HARP subsystem about configuration and physical interface
1478 * information for any currently registered ATM adapters. Store the information
1479 * as arrays for easier indexing by SNMP port/index numbers.
1485 * none Information from HARP available
1491 struct air_cfg_rsp *cfg_info = NULL;
1492 struct air_int_rsp *intf_info = NULL;
1496 * Get configuration info - what's available with 'atm sh config'
1498 buf_len = get_cfg_info ( NULL, &cfg_info );
1500 * If error occurred, clear out everything
1502 if ( buf_len <= 0 ) {
1503 UM_ZERO ( Cfg, sizeof(Cfg) );
1504 UM_ZERO ( Intf, sizeof(Intf) );
1510 * Move to local storage
1512 UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1514 * Compute how many units information was returned for
1516 NUnits = buf_len / sizeof(struct air_cfg_rsp);
1518 UM_FREE ( cfg_info );
1521 * Get the per interface information
1523 buf_len = get_intf_info ( NULL, &intf_info );
1525 * If error occurred, clear out Intf info
1527 if ( buf_len <= 0 ) {
1528 UM_ZERO ( Intf, sizeof(Intf) );
1533 * Move to local storage
1535 UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1537 UM_FREE ( intf_info );
1545 * Open a new SNMP session for ILMI
1547 * Start by updating interface information, in particular, how many
1548 * interfaces are in the system. While we'll try to open sessons on
1549 * all interfaces, this deamon currently can only handle the first
1562 struct sockaddr_atm satm;
1563 struct t_atm_aal5 aal5;
1564 struct t_atm_traffic traffic;
1565 struct t_atm_bearer bearer;
1566 struct t_atm_qos qos;
1567 struct t_atm_app_name appname;
1569 char nifname[IFNAMSIZ];
1576 for ( unit = 0; unit < NUnits; unit++ ) {
1579 * ILMI only makes sense for UNI signalling protocols
1581 sig_proto = Intf[unit].anp_sig_proto;
1582 if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1583 sig_proto != ATM_SIG_UNI40 )
1586 if ( ilmi_fd[unit] == -1 ) {
1588 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1590 if ( ilmi_fd[unit] < 0 ) {
1596 * Set interface name. For now, we must have a netif to go on...
1598 if ( Intf[unit].anp_nif_cnt == 0 ) {
1599 if ( Debug_Level > 1 && Log ) {
1601 fprintf ( Log, "No nif on unit %d\n", unit );
1603 close ( ilmi_fd[unit] );
1607 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1608 optlen = sizeof ( nifname );
1609 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1610 T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1611 perror ( "setsockopt" );
1615 "Couldn't set interface name \"%s\"\n",
1618 if ( Debug_Level > 1 && Log ) {
1620 fprintf ( Log, "nifname: closing unit %d\n", unit );
1622 close ( ilmi_fd[unit] );
1628 * Set up destination SAP
1630 UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
1631 satm.satm_family = AF_ATM;
1632 #if (defined(BSD) && (BSD >= 199103))
1633 satm.satm_len = sizeof(satm);
1636 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1637 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1638 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1639 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1640 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1642 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1645 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1646 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1647 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1649 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1651 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1654 * Set up connection parameters
1656 aal5.forward_max_SDU_size = MAX_LEN;
1657 aal5.backward_max_SDU_size = MAX_LEN;
1658 aal5.SSCS_type = T_ATM_NULL;
1659 optlen = sizeof(aal5);
1660 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1661 (caddr_t) &aal5, optlen ) < 0 ) {
1662 perror ( "setsockopt(aal5)" );
1663 if ( Debug_Level > 1 && Log ) {
1665 fprintf ( Log, "aal5: closing unit %d\n", unit );
1667 close ( ilmi_fd[unit] );
1672 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1673 traffic.forward.PCR_all_traffic = 100000;
1674 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1675 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1676 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1677 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1678 traffic.forward.tagging = T_NO;
1679 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1680 traffic.backward.PCR_all_traffic = 100000;
1681 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1682 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1683 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1684 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1685 traffic.backward.tagging = T_NO;
1686 traffic.best_effort = T_YES;
1687 optlen = sizeof(traffic);
1688 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1689 (caddr_t)&traffic, optlen) < 0) {
1690 perror("setsockopt(traffic)");
1692 bearer.bearer_class = T_ATM_CLASS_X;
1693 bearer.traffic_type = T_ATM_NULL;
1694 bearer.timing_requirements = T_ATM_NULL;
1695 bearer.clipping_susceptibility = T_NO;
1696 bearer.connection_configuration = T_ATM_1_TO_1;
1697 optlen = sizeof(bearer);
1698 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1699 (caddr_t)&bearer, optlen) < 0) {
1700 perror("setsockopt(bearer)");
1703 qos.coding_standard = T_ATM_NETWORK_CODING;
1704 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1705 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1706 optlen = sizeof(qos);
1707 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1709 perror("setsockopt(qos)");
1712 subaddr.address_format = T_ATM_ABSENT;
1713 subaddr.address_length = 0;
1714 optlen = sizeof(subaddr);
1715 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1716 (caddr_t)&subaddr, optlen) < 0) {
1717 perror("setsockopt(dest_sub)");
1720 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1721 optlen = sizeof(appname);
1722 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1723 (caddr_t)&appname, optlen) < 0) {
1724 perror("setsockopt(appname)");
1728 * Now try to connect to destination
1730 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1731 sizeof(satm)) < 0 ) {
1732 perror ( "connect" );
1733 if ( Debug_Level > 1 && Log ) {
1735 fprintf ( Log, "connect: closing unit %d\n", unit );
1737 close ( ilmi_fd[unit] );
1742 if ( Debug_Level && Log ) {
1744 fprintf ( Log, "***** opened unit %d\n", unit );
1747 ilmi_state[unit] = ILMI_COLDSTART;
1758 * Get our local IP address for this interface
1761 * s - socket to find address for
1762 * aval - pointer to variable to store address in
1769 get_local_ip ( int s, long *aval )
1771 char intf_name[IFNAMSIZ];
1772 int namelen = IFNAMSIZ;
1773 struct air_netif_rsp *net_info = NULL;
1774 struct sockaddr_in *sin;
1777 * Get physical interface name
1779 if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1780 (caddr_t) intf_name, &namelen ) )
1784 * Get network interface information for this physical interface
1786 get_netif_info ( intf_name, &net_info );
1787 if ( net_info == NULL )
1790 sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1795 UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1797 UM_FREE ( net_info );
1804 * Set local NSAP prefix and then reply with our full NSAP address.
1806 * Switch will send a SET message with the NSAP prefix after a coldStart.
1807 * We'll set that prefix into HARP and then send a SET message of our own
1808 * with our full interface NSAP address.
1811 * oid - objid from SET message
1812 * hdr - pointer to internal SNMP header
1813 * buf - pointer to SET buffer
1814 * s - socket to send messages on
1821 set_prefix ( Objid *oid, __unused Snmp_Header *hdr, int intf )
1823 struct atmsetreq asr;
1829 * Build IOCTL request to set prefix
1831 asr.asr_opcode = AIOCS_SET_PRF;
1832 strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1833 sizeof(asr.asr_prf_intf ) );
1835 * Pull prefix out of received Objid
1836 * save in set_prefix IOCTL and addressEntry table
1838 for ( i = 0; i < oid->oid[13]; i++ ) {
1839 asr.asr_prf_pref[i] = oid->oid[i + 14];
1843 * Pass new prefix to the HARP kernel
1845 fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1848 if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1849 if ( errno != EALREADY ) {
1850 syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1853 fprintf ( Log, "errno %d setting prefix\n",
1863 * Reload the cfg/intf info with newly set prefix
1867 aa = &Intf[intf].anp_addr;
1870 * Copy our NSAP into addressEntry table
1873 addressEntry[intf].oid[0] = 0;
1874 for ( i = 0; i < aa->address_length; i++ ) {
1875 addressEntry[intf].oid[0]++; /* Increment length */
1876 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1885 set_address ( __unused Snmp_Header *hdr, int intf )
1890 PDU_Header = build_generic_header();
1891 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
1892 var = PDU_Header->head;
1893 /* Copy generic addressEntry OBJID */
1894 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
1896 /* Set specific instance */
1897 i = var->oid.oid[0] + 1; /* Get length */
1898 var->oid.oid[i++] = 1;
1899 var->oid.oid[i++] = 1;
1900 var->oid.oid[i++] = 3;
1901 var->oid.oid[i++] = 0;
1903 /* Copy in address length */
1904 var->oid.oid[i++] = addressEntry[intf].oid[0];
1906 /* Copy in address */
1907 for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
1908 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
1909 var->oid.oid[0] = i - 1; /* Set new length */
1912 var->type = ASN_INTEGER;
1915 build_pdu ( PDU_Header, PDU_TYPE_SET );
1916 send_resp ( intf, PDU_Header, Resp_Buf );
1920 * Utility to strip off any leading path information from a filename
1923 * path pathname to strip
1926 * fname striped filename
1930 basename ( char *path )
1934 if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1943 * Increment Debug Level
1945 * Catches SIGUSR1 signal and increments value of Debug_Level
1948 * sig - signal number
1951 * none - Debug_Level incremented
1955 Increment_DL ( __unused int sig )
1958 if ( Debug_Level && Log == NULL ) {
1962 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
1966 setbuf ( Log, NULL );
1968 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
1971 signal ( SIGUSR1, Increment_DL );
1976 * Decrement Debug Level
1978 * Catches SIGUSR2 signal and decrements value of Debug_Level
1981 * sig - signal number
1984 * none - Debug_Level decremented
1988 Decrement_DL ( __unused int sig )
1991 if ( Debug_Level <= 0 ) {
1995 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
2001 signal ( SIGUSR2, Decrement_DL );
2006 * Loop through GET variable list looking for matches
2010 process_get ( Snmp_Header *hdr, int intf )
2017 idx = find_var ( var );
2020 var->type = ASN_OBJID;
2021 UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2022 (caddr_t)&var->var.oval,
2026 var->type = ASN_TIMESTAMP;
2027 var->var.ival = get_ticks();
2030 var->type = ASN_INTEGER;
2031 var->var.ival = UNITYPE_PRIVATE;
2034 var->type = ASN_INTEGER;
2035 switch ( Intf[intf].anp_sig_proto ) {
2037 var->var.ival = UNIVER_UNI30;
2040 var->var.ival = UNIVER_UNI31;
2043 var->var.ival = UNIVER_UNI40;
2046 var->var.ival = UNIVER_UNKNOWN;
2051 var->type = ASN_INTEGER;
2052 var->var.ival = DEVTYPE_USER;
2055 var->type = ASN_INTEGER;
2056 var->var.ival = 1024;
2059 var->type = ASN_INTEGER;
2060 var->var.ival = intf + 1;
2063 var->type = ASN_IPADDR;
2064 get_local_ip ( ilmi_fd[intf],
2070 var->type = ASN_INTEGER;
2071 var->var.ival = 0x30 + intf;
2074 var->type = ASN_OCTET;
2075 var->var.sval[0] = 6;
2076 UM_COPY ( (caddr_t)&Cfg[intf].acp_macaddr,
2077 (caddr_t)&var->var.sval[1], 6 );
2085 build_pdu ( hdr, PDU_TYPE_GETRESP );
2086 send_resp ( intf, hdr, Resp_Buf );
2091 * ILMI State Processing Loop
2096 ilmi_do_state (void)
2115 * SunOS CC doesn't allow automatic aggregate initialization.
2116 * Initialize to zero which effects a poll operation.
2122 * Clear fd_set and initialize to check this interface
2125 for ( intf = 0; intf < MAX_UNITS; intf++ )
2126 if ( ilmi_fd[intf] > 0 ) {
2127 FD_SET ( ilmi_fd[intf], &rfd );
2128 maxfd = MAX ( maxfd, ilmi_fd[intf] );
2132 * Check for new interfaces
2136 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2138 * Do any pre-message state processing
2140 switch ( ilmi_state[intf] ) {
2141 case ILMI_COLDSTART:
2143 * Clear addressTable
2145 UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2148 * Start by sending a COLD_START trap. This should cause the
2149 * remote end to clear the associated prefix/address table(s).
2151 /* Build ColdStart TRAP header */
2152 ColdStart_Header = build_cold_start();
2153 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2154 send_resp ( intf, ColdStart_Header, Resp_Buf );
2157 * Start a timeout so that if the next state fails, we re-enter
2162 /* Enter new state */
2163 ilmi_state[intf] = ILMI_INIT;
2164 /* fall into ILMI_INIT */
2168 * After a COLD_START, we need to check that the remote end has
2169 * cleared any tables. Send a GET_NEXT request to check for this.
2170 * In the event that the table is not empty, or that no reply is
2171 * received, return to COLD_START state.
2173 PDU_Header = build_generic_header();
2174 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
2175 var = PDU_Header->head;
2176 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2178 var->type = ASN_NULL;
2182 * Send GETNEXT request looking for empty ATM Address Table
2184 PDU_Header->reqid = Req_ID++;
2185 build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2186 send_resp ( intf, PDU_Header, Resp_Buf );
2189 * Start a timeout while looking for SET message. If we don't receive
2190 * a SET, then go back to COLD_START state.
2196 /* Normal SNMP processing */
2204 count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2206 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2208 * Check for received messages
2210 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2212 n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2213 if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2214 ilmi_state[intf] = ILMI_COLDSTART;
2215 close ( ilmi_fd[intf] );
2218 if ( Log && Debug_Level > 1 ) fprintf ( Log, "***** state %d ***** read %d bytes from %d (%d) ***** %s *****\n",
2219 ilmi_state[intf], n, intf, ilmi_fd[intf], PDU_Types[buf[14] - 0xA0] ); {
2220 if ( Debug_Level > 2 )
2221 hexdump ( (caddr_t)&buf[1], n );
2223 bpp = (caddr_t)&buf[1];
2224 if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2227 /* What we do with this messages depends upon the state we're in */
2228 switch ( ilmi_state[intf] ) {
2229 case ILMI_COLDSTART:
2230 /* We should never be in this state here */
2234 /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2235 switch ( Hdr->pdutype ) {
2236 case PDU_TYPE_GETNEXT:
2238 * Should be because the remote side is attempting
2239 * to verify that our table is empty
2241 if ( oid_ncmp ( &Hdr->head->oid,
2242 &Objids[ADDRESS_OBJID],
2243 Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2244 if ( addressEntry[intf].oid[0] ) {
2246 /* Our table is not empty - return address */
2249 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2250 send_resp ( intf, Hdr, Resp_Buf );
2252 case PDU_TYPE_GETRESP:
2254 * This should be in response to our GETNEXT.
2255 * Check the OIDs and go onto ILMI_RUNNING if
2256 * the address table is empty. We can cheat and
2257 * not check sequence numbers because we only send
2258 * the one GETNEXT request and ILMI says we shouldn't
2259 * have interleaved sessions.
2262 * First look for empty table. If found, go to next state.
2264 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2265 ((Hdr->error == SNMP_ERR_NOERROR) &&
2266 ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2267 Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2268 ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2269 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2271 * Check to see if this matches our address
2272 * and if so, that it's a VALID entry.
2278 aa = &Intf[intf].anp_addr;
2279 if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2280 for ( l = 0; l < aa->address_length; l++ ) {
2281 if ( (int)((u_char *)(aa->address))[l] !=
2282 Hdr->head->oid.oid[14 + l] ) {
2288 if ( Hdr->head->var.ival == 1 ) {
2289 ilmi_state[intf] = ILMI_RUNNING;
2296 /* Look for SET_PREFIX Objid */
2297 if ( oid_ncmp ( &Hdr->head->oid,
2298 &Objids[SETPFX_OBJID],
2299 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2300 set_prefix ( &Hdr->head->oid, Hdr, intf );
2301 /* Reply to SET before sending our ADDRESS */
2302 build_pdu(Hdr, PDU_TYPE_GETRESP);
2303 send_resp( intf, Hdr, Resp_Buf );
2304 set_address ( Hdr, intf );
2306 build_pdu(Hdr, PDU_TYPE_GETRESP);
2307 send_resp( intf, Hdr, Resp_Buf );
2311 /* Remote side wants us to start fresh */
2323 /* We'll take anything here */
2324 switch ( Hdr->pdutype ) {
2326 process_get ( Hdr, intf );
2328 case PDU_TYPE_GETRESP:
2329 /* Ignore GETRESPs */
2332 case PDU_TYPE_GETNEXT:
2333 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2334 send_resp ( intf, Hdr, Resp_Buf );
2337 /* Look for SET_PREFIX Objid */
2338 if ( oid_ncmp ( &Hdr->head->oid,
2339 &Objids[SETPFX_OBJID],
2340 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2341 set_prefix ( &Hdr->head->oid, Hdr, intf );
2342 /* Reply to SET before sending our ADDRESS */
2343 build_pdu(Hdr, PDU_TYPE_GETRESP);
2344 send_resp( intf, Hdr, Resp_Buf );
2345 set_address ( Hdr, intf );
2347 build_pdu(Hdr, PDU_TYPE_GETRESP);
2348 send_resp( intf, Hdr, Resp_Buf );
2362 } /* if received message */
2363 } /* for each interface */
2364 } /* for ever loop */
2369 main ( int argc, char *argv[] )
2373 int Reset = 0; /* Should we send a coldStart and exit? */
2376 * What are we running as? (argv[0])
2378 progname = strdup ( (char *)basename ( argv[0] ) );
2382 gethostname ( hostname, sizeof ( hostname ) );
2385 * Ilmid needs to run as root to set prefix
2387 if ( getuid() != 0 ) {
2388 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2395 while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2398 Debug_Level = atoi ( optarg );
2407 fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2415 * If we're not doing debugging, run in the background
2417 if ( foregnd == 0 ) {
2418 if ( daemon ( 0, 0 ) )
2419 err ( 1, "Can't fork" );
2422 signal ( SIGUSR1, Increment_DL );
2423 signal ( SIGUSR2, Decrement_DL );
2428 if ( Debug_Level ) {
2432 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2437 setbuf ( Log, NULL );
2440 * Get our startup time
2442 gettimeofday ( &starttime, NULL );
2444 starttime.tv_usec += 1000000;
2446 /* Randomize starting request ID */
2447 Req_ID = starttime.tv_sec;
2450 * Reset all the interface descriptors
2452 for ( i = 0; i < MAX_UNITS; i++ ) {
2456 * Try to open all the interfaces
2461 * If we're just sending a coldStart end exiting...
2464 for ( i = 0; i < MAX_UNITS; i++ )
2465 if ( ilmi_fd[i] >= 0 ) {
2466 /* Build ColdStart TRAP header */
2467 ColdStart_Header = build_cold_start();
2468 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2469 send_resp ( i, ColdStart_Header, Resp_Buf );
2470 if ( Debug_Level > 1 && Log ) {
2472 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2475 close ( ilmi_fd[i] );