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.8 2006/10/16 00:15:35 pavalos 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 const 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 const 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 const 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 static const char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
334 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
337 * Write a syslog() style timestamp
339 * Write a syslog() style timestamp with month, day, time and hostname
350 write_timestamp(void)
355 clk = time ( (time_t)NULL );
356 tm = localtime ( &clk );
358 if ( Log && Debug_Level > 1 )
360 fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
361 Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
362 tm->tm_sec, hostname );
369 * Utility to pretty print buffer as hex dumps
372 * bp - buffer pointer
373 * len - length to pretty print
380 hexdump ( u_char *bp, int len )
385 * Print as 4 groups of four bytes. Each byte is separated
386 * by a space, each block of four is separated, and two blocks
387 * of eight are also separated.
389 for ( i = 0; i < len; i += 16 ) {
392 for ( j = 0; j < 4 && j + i < len; j++ )
394 fprintf ( Log, "%.2x ", *bp++ );
396 fprintf ( Log, " " );
397 for ( ; j < 8 && j + i < len; j++ )
399 fprintf ( Log, "%.2x ", *bp++ );
401 fprintf ( Log, " " );
404 for ( ; j < 12 && j + i < len; j++ )
406 fprintf ( Log, "%.2x ", *bp++ );
408 fprintf ( Log, " " );
409 for ( ; j < 16 && j + i < len; j++ )
411 fprintf ( Log, "%.2x ", *bp++ );
413 fprintf ( Log, "\n" );
423 * Get lengths from PDU encodings
425 * Lengths are sometimes encoded as a single byte if the length
426 * is less the 127 but are more commonly encoded as one byte with
427 * the high bit set and the lower seven bits indicating the nuber
428 * of bytes which make up the length value. Trailing data is (to my
429 * knowledge) not 7-bit encoded.
432 * bufp - pointer to buffer pointer
433 * plen - pointer to PDU length or NULL if not a concern
436 * bufp - updated buffer pointer
437 * plen - (possibly) adjusted pdu length
438 * <len> - decoded length
442 asn_get_pdu_len ( u_char **bufp, int *plen )
452 for ( i = 0; i < (b & ~0x80); i++ ) {
453 len = len * 256 + *bp++;
465 * Get an 7-bit encoded value.
467 * Get a value which is represented using a 7-bit encoding. The last
468 * byte in the stream has the high-bit clear.
471 * bufp - pointer to the buffer pointer
472 * len - pointer to the buffer length
475 * bufp - updated buffer pointer
476 * len - updated buffer length
477 * <val> - value encoding represented
481 asn_get_encoded ( u_char **bufp, int *len )
488 * Keep going while high bit is set
492 * Each byte can represent 7 bits
494 val = ( val << 7 ) + ( *bp & ~0x80 );
496 } while ( *bp++ & 0x80 );
498 *bufp = bp; /* update buffer pointer */
499 *len = l; /* update buffer length */
505 * Get a BER encoded integer
507 * Intergers are encoded as one byte length followed by <length> data bytes
510 * bufp - pointer to the buffer pointer
511 * plen - pointer to PDU length or NULL if not a concern
514 * bufp - updated buffer pointer
515 * plen - (possibly) updated PDU length
516 * <val> - value of encoded integer
520 asn_get_int ( u_char **bufp, int *plen )
530 for ( i = 0; i < len; i++ ) {
531 v = (v * 256) + *bp++;
540 * Set a BER encoded integer
543 * bufp - pointer to buffer pointer where we are to set int in
544 * val - integer value to set
548 * <bufp> - updated buffer pointer
552 asn_set_int ( u_char **bufp, int val )
558 int len = sizeof(int);
562 /* Check for special case where val == 0 */
572 while ( u.c[i] == 0 && i++ < sizeof(int) )
575 if ( u.c[i] > 0x7f ) {
581 UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
589 * Utility to print a object identifier
592 * objid - pointer to objid representation
599 print_objid ( Objid *objid )
604 * First oid coded as 40 * X + Y
608 fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
609 objid->oid[1] % 40 );
611 for ( i = 2; i <= objid->oid[0]; i++ )
613 fprintf ( Log, ".%d", objid->oid[i] );
615 fprintf ( Log, "\n" );
621 * Get Object Identifier
624 * bufp - pointer to buffer pointer
625 * objid - pointer to objid buffer
626 * plen - pointer to PDU length or NULL of not a concern
629 * bufp - updated buffer pointer
630 * objid - internal representation of encoded objid
631 * plen - (possibly) adjusted PDU length
635 asn_get_objid ( u_char **bufp, Objid *objid, int *plen )
639 int *ip = (int *)objid + 1; /* First byte will contain length */
646 *ip++ = asn_get_encoded ( &bp, &len );
651 objid->oid[0] = oidlen;
658 * Put OBJID - assumes elements <= 16383 for two byte coding
662 asn_put_objid ( u_char **bufp, Objid *objid )
670 *bp++ = objid->oid[0];
672 for ( i = 1; i <= objid->oid[0]; i++ ) {
673 u_int c = objid->oid[i];
676 *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
678 c &= 0x7f; /* XXX - assumption of two bytes */
693 * Octet strings are encoded as a 7-bit encoded length followed by <len>
697 * bufp - pointer to buffer pointer
698 * octet - pointer to octet buffer
699 * plen - pointer to PDU length
702 * bufp - updated buffer pointer
703 * octet - encoded Octet String
704 * plen - (possibly) adjusted PDU length
708 asn_get_octet ( u_char **bufp, char *octet, int *plen )
715 * &i is really a dummy value here as we don't keep track
716 * of the ongoing buffer length
718 len = asn_get_encoded ( &bp, &i );
720 for ( i = 0; i < len; i++ ) {
733 * Utility to print SNMP PDU header information
736 * Hdr - pointer to internal SNMP header structure
743 print_header ( Snmp_Header *Hdr )
750 "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x %s\n",
751 Hdr->pdulen, Hdr->version + 1, Hdr->community,
752 Hdr->pdutype, PDU_Types[Hdr->pdutype - PDU_TYPE_GET] );
754 if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
755 fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
756 Hdr->reqid, Hdr->error, Hdr->erridx );
763 fprintf ( Log, " Variable Type: %d", var->type );
764 if ( Var_Types[var->type] )
765 fprintf ( Log, " %s", Var_Types[var->type] );
766 fprintf ( Log, "\n\tObject: " );
767 print_objid ( &var->oid );
768 fprintf ( Log, "\tValue: " );
769 switch ( var->type ) {
771 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
774 fprintf ( Log, "NULL" );
777 fprintf ( Log, "[0x%x]", var->type );
780 fprintf ( Log, "\n" );
790 * Pull OID's from GET/SET message
793 * h - pointer to Snmp_Header
794 * bp - pointer to input PDU
801 parse_oids ( Snmp_Header *h, u_char **bp )
809 if ( *bufp++ == ASN_SEQUENCE ) {
812 /* Create new Variable instance */
813 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
821 /* Set head iff NULL */
822 if ( h->head == NULL ) {
828 /* Get length of variable sequence */
829 sublen = asn_get_pdu_len ( &bufp, &len );
830 /* Should be OBJID type */
831 if ( *bufp++ != ASN_OBJID ) {
835 asn_get_objid ( &bufp, &var->oid, &len );
838 switch ( var->type ) {
840 var->var.ival = asn_get_int ( &bufp, &len );
847 asn_get_objid ( &bufp, &var->var.oval, &len );
850 asn_get_octet ( &bufp, var->var.sval, &len );
855 fprintf ( Log, "Unknown variable type: %d\n",
870 * Crack the SNMP header
872 * Pull the PDU length, SNMP version, SNMP community and PDU type.
873 * If present, also pull out the Request ID, Error status, and Error
877 * bufp - pointer to buffer pointer
880 * bufp - updated buffer pointer
881 * - generated SNMP header
885 asn_get_header ( u_char **bufp )
893 * Allocate memory to hold the SNMP header
895 if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
896 return ( (Snmp_Header *)NULL );
899 * Ensure that we wipe the slate clean
901 UM_ZERO ( h, sizeof ( Snmp_Header ) );
904 * PDU has to start as SEQUENCE OF
906 if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
907 return ( (Snmp_Header *)NULL );
910 * Get the length of remaining PDU data
912 h->pdulen = asn_get_pdu_len ( &bp, NULL );
915 * We expect to find an integer encoding Version-1
917 if ( *bp++ != ASN_INTEGER ) {
918 return ( (Snmp_Header *)NULL );
920 h->version = asn_get_int ( &bp, NULL );
923 * After the version, we need the community name
925 if ( *bp++ != ASN_OCTET ) {
926 return ( (Snmp_Header *)NULL );
928 asn_get_octet ( &bp, h->community, NULL );
931 * Single byte PDU type
936 * If this isn't a TRAP PDU, then look for the rest of the header
938 if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
940 asn_get_pdu_len ( &bp, &dummy );
943 if ( *bp++ != ASN_INTEGER ) {
945 return ( (Snmp_Header *)NULL );
947 h->reqid = asn_get_int ( &bp, NULL );
950 if ( *bp++ != ASN_INTEGER ) {
952 return ( (Snmp_Header *)NULL );
954 h->error = asn_get_int ( &bp, NULL );
957 if ( *bp++ != ASN_INTEGER ) {
959 return ( (Snmp_Header *)NULL );
961 h->erridx = asn_get_int ( &bp, NULL );
964 if ( *bp++ != ASN_SEQUENCE ) {
966 return ( (Snmp_Header *)NULL );
968 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
969 h->varlen += ( len - 1 );
971 parse_oids ( h, &bp );
976 if ( Log && Debug_Level )
984 * Compare two internal OID representations
987 * oid1 - Internal Object Identifier
988 * oid2 - Internal Object Identifier
992 * 1 - Objid's don't match
996 oid_cmp ( Objid *oid1, Objid *oid2 )
1004 if ( !(oid1->oid[0] == oid2->oid[0] ) )
1005 /* Different lengths */
1011 * value by value compare
1013 for ( i = 1; i <= len; i++ ) {
1014 if ( !(oid1->oid[i] == oid2->oid[i]) )
1015 /* values don't match */
1019 /* Objid's are identical */
1024 * Compare two internal OID representations
1027 * oid1 - Internal Object Identifier
1028 * oid2 - Internal Object Identifier
1029 * len - Length of OID to compare
1033 * 1 - Objid's don't match
1037 oid_ncmp ( Objid *oid1, Objid *oid2, int len )
1042 * value by value compare
1044 for ( i = 1; i <= len; i++ ) {
1045 if ( !(oid1->oid[i] == oid2->oid[i]) )
1046 /* values don't match */
1050 /* Objid's are identical */
1055 * Find the index of a OBJID which matches this Variable instance
1058 * var - pointer to Variable instance
1061 * idx - index of matched Variable instance
1062 * -1 - no matching Variable found
1066 find_var ( Variable *var )
1070 for ( i = 0; i < NUM_OIDS; i++ )
1071 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1080 * Return the time process has been running as a number of ticks
1092 struct timeval timenow;
1093 struct timeval timediff;
1095 gettimeofday ( &timenow, NULL );
1097 * Adjust for subtraction
1100 timenow.tv_usec += 1000000;
1103 * Compute time since 'starttime'
1105 timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1106 timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1109 * Adjust difference timeval
1111 if ( timediff.tv_usec >= 1000000 ) {
1112 timediff.tv_usec -= 1000000;
1117 * Compute number of ticks
1119 return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1124 * Build a response PDU
1127 * hdr - pointer to PDU Header with completed Variable list
1134 build_pdu ( Snmp_Header *hdr, int type )
1136 u_char *bp = Resp_Buf;
1147 * Clear out the reply
1149 UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1151 /* [0] is reserved for overall length */
1154 /* Start with SEQUENCE OF */
1155 *bp++ = ASN_SEQUENCE;
1156 /* - assume we can code length in two octets */
1161 *bp++ = ASN_INTEGER;
1162 asn_set_int ( &bp, hdr->version );
1163 /* Community name */
1165 *bp++ = strlen ( hdr->community );
1166 UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1167 bp += strlen ( hdr->community );
1171 /* Length of OID data - assume it'll fit in one octet */
1174 if ( type != PDU_TYPE_TRAP ) {
1176 *bp++ = ASN_INTEGER;
1177 asn_set_int ( &bp, hdr->reqid );
1179 * Check to see if all the vaiables were resolved - we do this
1180 * by looking for something which still has a ASN_NULL value.
1183 if ( type == PDU_TYPE_GETRESP ) {
1184 while ( var && erridx == 0 ) {
1185 if ( var->type != ASN_NULL ) {
1194 *bp++ = ASN_INTEGER;
1195 *bp++ = 0x01; /* length = 1 */
1197 *bp++ = SNMP_ERR_NOSUCHNAME;
1199 *bp++ = SNMP_ERR_NOERROR;
1201 *bp++ = ASN_INTEGER;
1202 *bp++ = 0x01; /* length = 1 */
1203 *bp++ = erridx; /* index - 0 if no error */
1205 /* type == PDU_TYPE_TRAP */
1207 /* Fill in ENTERPRISE OBJID */
1209 asn_put_objid ( &bp, &hdr->enterprise );
1211 /* Fill in IP address */
1213 *bp++ = sizeof ( hdr->ipaddr );
1214 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1215 bp += sizeof(hdr->ipaddr);
1217 /* Fill in generic and specific trap types */
1218 *bp++ = ASN_INTEGER;
1219 asn_set_int ( &bp, hdr->generic_trap );
1220 *bp++ = ASN_INTEGER;
1221 asn_set_int ( &bp, hdr->specific_trap );
1223 /* Fill in time-stamp - assume 0 for now */
1224 *bp++ = ASN_TIMESTAMP;
1225 asn_set_int ( &bp, 0 );
1227 /* encoded length */
1228 traplen = ( bp - ppp - 1 );
1230 /* Continue with variable processing */
1234 *bp++ = ASN_SEQUENCE;
1236 /* - assume we can code length in two octets */
1242 /* Install Variables */
1250 *bp++ = ASN_SEQUENCE;
1252 /* - assume we can code length in two octets */
1259 len += asn_put_objid ( &bp, &var->oid );
1261 if ( erridx && varidx >= erridx ) {
1262 /* Code this variable as NULL */
1273 switch ( var->type ) {
1275 asn_set_int ( &bp, var->var.ival );
1276 len += ( *lpp + 1 );
1279 *bp++ = var->var.sval[0];
1281 UM_COPY ( (caddr_t)&var->var.sval[1],
1282 bp, var->var.sval[0] );
1283 len += var->var.sval[0];
1284 bp += var->var.sval[0];
1291 len += asn_put_objid ( &bp, &var->var.oval );
1298 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1303 asn_set_int ( &bp, var->var.ival );
1304 len += ( *lpp + 1 );
1311 /* Accumulate total Variable sequence length */
1312 varlen += (len + 4);
1314 /* Fill in length of this sequence */
1315 bpp[1] = len & 0xff;
1322 /* Fill in length of Variable sequence */
1323 vpp[1] = varlen & 0xff;
1324 vpp[0] = varlen >> 8;
1326 if ( type != PDU_TYPE_TRAP ) {
1327 /* Fill in length of data AFTER PDU type */
1328 *ppp = varlen + 12 + ppp[2]; /* + length of reqid */
1330 /* Fill in length of data AFTER PDU type */
1331 *ppp = varlen + traplen + 4; /* + length of initial sequence of */
1334 /* Fill in overall sequence length */
1335 pdulen = *ppp + 7 + strlen ( hdr->community );
1336 Resp_Buf[4] = pdulen & 0x7f;
1337 Resp_Buf[3] = pdulen >> 8;
1339 pdulen = bp - Resp_Buf - 1;
1341 Resp_Buf[0] = pdulen;
1343 hdr->pdutype = type;
1349 free_pdu ( Snmp_Header *hdr )
1353 while ( hdr->head ) {
1354 var = hdr->head->next; /* Save next link */
1355 UM_FREE ( hdr->head ); /* Free current var */
1356 hdr->head = var; /* Set head to next link */
1359 UM_FREE ( hdr ); /* Free fixed portion */
1364 * Set Request ID in PDU
1367 * resp - Response PDU buffer
1368 * reqid - request id value
1371 * none - request id may/may not be set
1375 set_reqid ( u_char *resp, int reqid )
1377 u_char *bp = (u_char *)&resp[18];
1386 * Replace the current Request ID with the supplied value
1388 UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1395 * Send a generic response packet
1398 * sd - socket to send the reply on
1399 * reqid - original request ID from GET PDU
1400 * resp - pointer to the response to send
1403 * none - response sent
1407 send_resp ( int intf, Snmp_Header *Hdr, u_char *resp )
1411 if ( ilmi_fd[intf] > 0 ) {
1412 n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1413 if ( Log && Debug_Level > 1 ) {
1415 fprintf ( Log, "===== Sent %d of %d bytes (%d) =====\n", n, resp[0], ilmi_fd[intf] );
1416 print_header ( Hdr );
1417 if ( Debug_Level > 2 )
1418 hexdump ( (u_char *)&resp[1], resp[0] );
1427 * Build a COLD_START TRAP PDU
1430 static Snmp_Header *
1431 build_cold_start(void)
1436 hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1439 hdr->version = SNMP_VERSION_1 - 1;
1440 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1442 hdr->ipaddr = 0x0; /* 0.0.0.0 */
1443 hdr->generic_trap = TRAP_COLDSTART;
1444 hdr->specific_trap = 0;
1445 UM_COPY ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1448 hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1450 UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1452 var->type = ASN_NULL;
1458 * Build a Generic PDU Header
1461 static Snmp_Header *
1462 build_generic_header(void)
1466 hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1469 hdr->version = SNMP_VERSION_1 - 1;
1470 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1476 * Initialize information on what physical adapters HARP knows about
1478 * Query the HARP subsystem about configuration and physical interface
1479 * information for any currently registered ATM adapters. Store the information
1480 * as arrays for easier indexing by SNMP port/index numbers.
1486 * none Information from HARP available
1492 struct air_cfg_rsp *cfg_info = NULL;
1493 struct air_int_rsp *intf_info = NULL;
1497 * Get configuration info - what's available with 'atm sh config'
1499 buf_len = get_cfg_info ( NULL, &cfg_info );
1501 * If error occurred, clear out everything
1503 if ( buf_len <= 0 ) {
1504 UM_ZERO ( Cfg, sizeof(Cfg) );
1505 UM_ZERO ( Intf, sizeof(Intf) );
1511 * Move to local storage
1513 UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1515 * Compute how many units information was returned for
1517 NUnits = buf_len / sizeof(struct air_cfg_rsp);
1519 UM_FREE ( cfg_info );
1522 * Get the per interface information
1524 buf_len = get_intf_info ( NULL, &intf_info );
1526 * If error occurred, clear out Intf info
1528 if ( buf_len <= 0 ) {
1529 UM_ZERO ( Intf, sizeof(Intf) );
1534 * Move to local storage
1536 UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1538 UM_FREE ( intf_info );
1546 * Open a new SNMP session for ILMI
1548 * Start by updating interface information, in particular, how many
1549 * interfaces are in the system. While we'll try to open sessons on
1550 * all interfaces, this deamon currently can only handle the first
1563 struct sockaddr_atm satm;
1564 struct t_atm_aal5 aal5;
1565 struct t_atm_traffic traffic;
1566 struct t_atm_bearer bearer;
1567 struct t_atm_qos qos;
1568 struct t_atm_app_name appname;
1570 char nifname[IFNAMSIZ];
1577 for ( unit = 0; unit < NUnits; unit++ ) {
1580 * ILMI only makes sense for UNI signalling protocols
1582 sig_proto = Intf[unit].anp_sig_proto;
1583 if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1584 sig_proto != ATM_SIG_UNI40 )
1587 if ( ilmi_fd[unit] == -1 ) {
1589 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1591 if ( ilmi_fd[unit] < 0 ) {
1597 * Set interface name. For now, we must have a netif to go on...
1599 if ( Intf[unit].anp_nif_cnt == 0 ) {
1600 if ( Debug_Level > 1 && Log ) {
1602 fprintf ( Log, "No nif on unit %d\n", unit );
1604 close ( ilmi_fd[unit] );
1608 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1609 optlen = sizeof ( nifname );
1610 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1611 T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1612 perror ( "setsockopt" );
1616 "Couldn't set interface name \"%s\"\n",
1619 if ( Debug_Level > 1 && Log ) {
1621 fprintf ( Log, "nifname: closing unit %d\n", unit );
1623 close ( ilmi_fd[unit] );
1629 * Set up destination SAP
1631 UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
1632 satm.satm_family = AF_ATM;
1633 #if (defined(BSD) && (BSD >= 199103))
1634 satm.satm_len = sizeof(satm);
1637 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1638 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1639 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1640 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1641 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1643 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1646 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1647 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1648 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1650 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1652 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1655 * Set up connection parameters
1657 aal5.forward_max_SDU_size = MAX_LEN;
1658 aal5.backward_max_SDU_size = MAX_LEN;
1659 aal5.SSCS_type = T_ATM_NULL;
1660 optlen = sizeof(aal5);
1661 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1662 (caddr_t) &aal5, optlen ) < 0 ) {
1663 perror ( "setsockopt(aal5)" );
1664 if ( Debug_Level > 1 && Log ) {
1666 fprintf ( Log, "aal5: closing unit %d\n", unit );
1668 close ( ilmi_fd[unit] );
1673 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1674 traffic.forward.PCR_all_traffic = 100000;
1675 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1676 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1677 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1678 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1679 traffic.forward.tagging = T_NO;
1680 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1681 traffic.backward.PCR_all_traffic = 100000;
1682 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1683 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1684 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1685 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1686 traffic.backward.tagging = T_NO;
1687 traffic.best_effort = T_YES;
1688 optlen = sizeof(traffic);
1689 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1690 (caddr_t)&traffic, optlen) < 0) {
1691 perror("setsockopt(traffic)");
1693 bearer.bearer_class = T_ATM_CLASS_X;
1694 bearer.traffic_type = T_ATM_NULL;
1695 bearer.timing_requirements = T_ATM_NULL;
1696 bearer.clipping_susceptibility = T_NO;
1697 bearer.connection_configuration = T_ATM_1_TO_1;
1698 optlen = sizeof(bearer);
1699 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1700 (caddr_t)&bearer, optlen) < 0) {
1701 perror("setsockopt(bearer)");
1704 qos.coding_standard = T_ATM_NETWORK_CODING;
1705 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1706 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1707 optlen = sizeof(qos);
1708 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1710 perror("setsockopt(qos)");
1713 subaddr.address_format = T_ATM_ABSENT;
1714 subaddr.address_length = 0;
1715 optlen = sizeof(subaddr);
1716 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1717 (caddr_t)&subaddr, optlen) < 0) {
1718 perror("setsockopt(dest_sub)");
1721 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1722 optlen = sizeof(appname);
1723 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1724 (caddr_t)&appname, optlen) < 0) {
1725 perror("setsockopt(appname)");
1729 * Now try to connect to destination
1731 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1732 sizeof(satm)) < 0 ) {
1733 perror ( "connect" );
1734 if ( Debug_Level > 1 && Log ) {
1736 fprintf ( Log, "connect: closing unit %d\n", unit );
1738 close ( ilmi_fd[unit] );
1743 if ( Debug_Level && Log ) {
1745 fprintf ( Log, "***** opened unit %d\n", unit );
1748 ilmi_state[unit] = ILMI_COLDSTART;
1759 * Get our local IP address for this interface
1762 * s - socket to find address for
1763 * aval - pointer to variable to store address in
1770 get_local_ip ( int s, long *aval )
1772 char intf_name[IFNAMSIZ];
1773 int namelen = IFNAMSIZ;
1774 struct air_netif_rsp *net_info = NULL;
1775 struct sockaddr_in *sin;
1778 * Get physical interface name
1780 if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1781 (caddr_t) intf_name, &namelen ) )
1785 * Get network interface information for this physical interface
1787 get_netif_info ( intf_name, &net_info );
1788 if ( net_info == NULL )
1791 sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1796 UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1798 UM_FREE ( net_info );
1805 * Set local NSAP prefix and then reply with our full NSAP address.
1807 * Switch will send a SET message with the NSAP prefix after a coldStart.
1808 * We'll set that prefix into HARP and then send a SET message of our own
1809 * with our full interface NSAP address.
1812 * oid - objid from SET message
1813 * hdr - pointer to internal SNMP header
1814 * buf - pointer to SET buffer
1815 * s - socket to send messages on
1822 set_prefix ( Objid *oid, __unused Snmp_Header *hdr, int intf )
1824 struct atmsetreq asr;
1830 * Build IOCTL request to set prefix
1832 asr.asr_opcode = AIOCS_SET_PRF;
1833 strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1834 sizeof(asr.asr_prf_intf ) );
1836 * Pull prefix out of received Objid
1837 * save in set_prefix IOCTL and addressEntry table
1839 for ( i = 0; i < oid->oid[13]; i++ ) {
1840 asr.asr_prf_pref[i] = oid->oid[i + 14];
1844 * Pass new prefix to the HARP kernel
1846 fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1849 if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1850 if ( errno != EALREADY ) {
1851 syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1854 fprintf ( Log, "errno %d setting prefix\n",
1864 * Reload the cfg/intf info with newly set prefix
1868 aa = &Intf[intf].anp_addr;
1871 * Copy our NSAP into addressEntry table
1874 addressEntry[intf].oid[0] = 0;
1875 for ( i = 0; i < aa->address_length; i++ ) {
1876 addressEntry[intf].oid[0]++; /* Increment length */
1877 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1886 set_address ( __unused Snmp_Header *hdr, int intf )
1891 PDU_Header = build_generic_header();
1892 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
1893 var = PDU_Header->head;
1894 /* Copy generic addressEntry OBJID */
1895 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
1897 /* Set specific instance */
1898 i = var->oid.oid[0] + 1; /* Get length */
1899 var->oid.oid[i++] = 1;
1900 var->oid.oid[i++] = 1;
1901 var->oid.oid[i++] = 3;
1902 var->oid.oid[i++] = 0;
1904 /* Copy in address length */
1905 var->oid.oid[i++] = addressEntry[intf].oid[0];
1907 /* Copy in address */
1908 for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
1909 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
1910 var->oid.oid[0] = i - 1; /* Set new length */
1913 var->type = ASN_INTEGER;
1916 build_pdu ( PDU_Header, PDU_TYPE_SET );
1917 send_resp ( intf, PDU_Header, Resp_Buf );
1921 * Utility to strip off any leading path information from a filename
1924 * path pathname to strip
1927 * fname striped filename
1931 basename ( char *path )
1935 if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1944 * Increment Debug Level
1946 * Catches SIGUSR1 signal and increments value of Debug_Level
1949 * sig - signal number
1952 * none - Debug_Level incremented
1956 Increment_DL ( __unused int sig )
1959 if ( Debug_Level && Log == (FILE *)NULL ) {
1963 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
1967 setbuf ( Log, NULL );
1969 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
1972 signal ( SIGUSR1, Increment_DL );
1977 * Decrement Debug Level
1979 * Catches SIGUSR2 signal and decrements value of Debug_Level
1982 * sig - signal number
1985 * none - Debug_Level decremented
1989 Decrement_DL ( __unused int sig )
1992 if ( Debug_Level <= 0 ) {
1996 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
2002 signal ( SIGUSR2, Decrement_DL );
2007 * Loop through GET variable list looking for matches
2011 process_get ( Snmp_Header *hdr, int intf )
2018 idx = find_var ( var );
2021 var->type = ASN_OBJID;
2022 UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2023 (caddr_t)&var->var.oval,
2027 var->type = ASN_TIMESTAMP;
2028 var->var.ival = get_ticks();
2031 var->type = ASN_INTEGER;
2032 var->var.ival = UNITYPE_PRIVATE;
2035 var->type = ASN_INTEGER;
2036 switch ( Intf[intf].anp_sig_proto ) {
2038 var->var.ival = UNIVER_UNI30;
2041 var->var.ival = UNIVER_UNI31;
2044 var->var.ival = UNIVER_UNI40;
2047 var->var.ival = UNIVER_UNKNOWN;
2052 var->type = ASN_INTEGER;
2053 var->var.ival = DEVTYPE_USER;
2056 var->type = ASN_INTEGER;
2057 var->var.ival = 1024;
2060 var->type = ASN_INTEGER;
2061 var->var.ival = intf + 1;
2064 var->type = ASN_IPADDR;
2065 get_local_ip ( ilmi_fd[intf],
2071 var->type = ASN_INTEGER;
2072 var->var.ival = 0x30 + intf;
2075 var->type = ASN_OCTET;
2076 var->var.sval[0] = 6;
2077 UM_COPY ( (caddr_t)&Cfg[intf].acp_macaddr,
2078 (caddr_t)&var->var.sval[1], 6 );
2086 build_pdu ( hdr, PDU_TYPE_GETRESP );
2087 send_resp ( intf, hdr, Resp_Buf );
2092 * ILMI State Processing Loop
2097 ilmi_do_state (void)
2116 * SunOS CC doesn't allow automatic aggregate initialization.
2117 * Initialize to zero which effects a poll operation.
2123 * Clear fd_set and initialize to check this interface
2126 for ( intf = 0; intf < MAX_UNITS; intf++ )
2127 if ( ilmi_fd[intf] > 0 ) {
2128 FD_SET ( ilmi_fd[intf], &rfd );
2129 maxfd = MAX ( maxfd, ilmi_fd[intf] );
2133 * Check for new interfaces
2137 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2139 * Do any pre-message state processing
2141 switch ( ilmi_state[intf] ) {
2142 case ILMI_COLDSTART:
2144 * Clear addressTable
2146 UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2149 * Start by sending a COLD_START trap. This should cause the
2150 * remote end to clear the associated prefix/address table(s).
2152 /* Build ColdStart TRAP header */
2153 ColdStart_Header = build_cold_start();
2154 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2155 send_resp ( intf, ColdStart_Header, Resp_Buf );
2158 * Start a timeout so that if the next state fails, we re-enter
2163 /* Enter new state */
2164 ilmi_state[intf] = ILMI_INIT;
2165 /* fall into ILMI_INIT */
2169 * After a COLD_START, we need to check that the remote end has
2170 * cleared any tables. Send a GET_NEXT request to check for this.
2171 * In the event that the table is not empty, or that no reply is
2172 * received, return to COLD_START state.
2174 PDU_Header = build_generic_header();
2175 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
2176 var = PDU_Header->head;
2177 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2179 var->type = ASN_NULL;
2183 * Send GETNEXT request looking for empty ATM Address Table
2185 PDU_Header->reqid = Req_ID++;
2186 build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2187 send_resp ( intf, PDU_Header, Resp_Buf );
2190 * Start a timeout while looking for SET message. If we don't receive
2191 * a SET, then go back to COLD_START state.
2197 /* Normal SNMP processing */
2205 count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2207 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2209 * Check for received messages
2211 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2213 n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2214 if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2215 ilmi_state[intf] = ILMI_COLDSTART;
2216 close ( ilmi_fd[intf] );
2219 if ( Log && Debug_Level > 1 ) fprintf ( Log, "***** state %d ***** read %d bytes from %d (%d) ***** %s *****\n",
2220 ilmi_state[intf], n, intf, ilmi_fd[intf], PDU_Types[buf[14] - 0xA0] ); {
2221 if ( Debug_Level > 2 )
2222 hexdump ( (caddr_t)&buf[1], n );
2224 bpp = (caddr_t)&buf[1];
2225 if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2228 /* What we do with this messages depends upon the state we're in */
2229 switch ( ilmi_state[intf] ) {
2230 case ILMI_COLDSTART:
2231 /* We should never be in this state here */
2235 /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2236 switch ( Hdr->pdutype ) {
2237 case PDU_TYPE_GETNEXT:
2239 * Should be because the remote side is attempting
2240 * to verify that our table is empty
2242 if ( oid_ncmp ( &Hdr->head->oid,
2243 &Objids[ADDRESS_OBJID],
2244 Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2245 if ( addressEntry[intf].oid[0] ) {
2247 /* Our table is not empty - return address */
2250 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2251 send_resp ( intf, Hdr, Resp_Buf );
2253 case PDU_TYPE_GETRESP:
2255 * This should be in response to our GETNEXT.
2256 * Check the OIDs and go onto ILMI_RUNNING if
2257 * the address table is empty. We can cheat and
2258 * not check sequence numbers because we only send
2259 * the one GETNEXT request and ILMI says we shouldn't
2260 * have interleaved sessions.
2263 * First look for empty table. If found, go to next state.
2265 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2266 ((Hdr->error == SNMP_ERR_NOERROR) &&
2267 ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2268 Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2269 ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2270 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2272 * Check to see if this matches our address
2273 * and if so, that it's a VALID entry.
2279 aa = &Intf[intf].anp_addr;
2280 if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2281 for ( l = 0; l < aa->address_length; l++ ) {
2282 if ( (int)((u_char *)(aa->address))[l] !=
2283 Hdr->head->oid.oid[14 + l] ) {
2289 if ( Hdr->head->var.ival == 1 ) {
2290 ilmi_state[intf] = ILMI_RUNNING;
2297 /* Look for SET_PREFIX Objid */
2298 if ( oid_ncmp ( &Hdr->head->oid,
2299 &Objids[SETPFX_OBJID],
2300 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2301 set_prefix ( &Hdr->head->oid, Hdr, intf );
2302 /* Reply to SET before sending our ADDRESS */
2303 build_pdu(Hdr, PDU_TYPE_GETRESP);
2304 send_resp( intf, Hdr, Resp_Buf );
2305 set_address ( Hdr, intf );
2307 build_pdu(Hdr, PDU_TYPE_GETRESP);
2308 send_resp( intf, Hdr, Resp_Buf );
2312 /* Remote side wants us to start fresh */
2324 /* We'll take anything here */
2325 switch ( Hdr->pdutype ) {
2327 process_get ( Hdr, intf );
2329 case PDU_TYPE_GETRESP:
2330 /* Ignore GETRESPs */
2333 case PDU_TYPE_GETNEXT:
2334 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2335 send_resp ( intf, Hdr, Resp_Buf );
2338 /* Look for SET_PREFIX Objid */
2339 if ( oid_ncmp ( &Hdr->head->oid,
2340 &Objids[SETPFX_OBJID],
2341 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2342 set_prefix ( &Hdr->head->oid, Hdr, intf );
2343 /* Reply to SET before sending our ADDRESS */
2344 build_pdu(Hdr, PDU_TYPE_GETRESP);
2345 send_resp( intf, Hdr, Resp_Buf );
2346 set_address ( Hdr, intf );
2348 build_pdu(Hdr, PDU_TYPE_GETRESP);
2349 send_resp( intf, Hdr, Resp_Buf );
2363 } /* if received message */
2364 } /* for each interface */
2365 } /* for ever loop */
2370 main ( int argc, char *argv[] )
2374 int Reset = 0; /* Should we send a coldStart and exit? */
2377 * What are we running as? (argv[0])
2379 progname = strdup ( (char *)basename ( argv[0] ) );
2383 gethostname ( hostname, sizeof ( hostname ) );
2386 * Ilmid needs to run as root to set prefix
2388 if ( getuid() != 0 ) {
2389 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2396 while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2399 Debug_Level = atoi ( optarg );
2408 fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2416 * If we're not doing debugging, run in the background
2418 if ( foregnd == 0 ) {
2419 if ( daemon ( 0, 0 ) )
2420 err ( 1, "Can't fork" );
2423 signal ( SIGUSR1, Increment_DL );
2424 signal ( SIGUSR2, Decrement_DL );
2429 if ( Debug_Level ) {
2433 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2438 setbuf ( Log, NULL );
2441 * Get our startup time
2443 gettimeofday ( &starttime, NULL );
2445 starttime.tv_usec += 1000000;
2447 /* Randomize starting request ID */
2448 Req_ID = starttime.tv_sec;
2451 * Reset all the interface descriptors
2453 for ( i = 0; i < MAX_UNITS; i++ ) {
2457 * Try to open all the interfaces
2462 * If we're just sending a coldStart end exiting...
2465 for ( i = 0; i < MAX_UNITS; i++ )
2466 if ( ilmi_fd[i] >= 0 ) {
2467 /* Build ColdStart TRAP header */
2468 ColdStart_Header = build_cold_start();
2469 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2470 send_resp ( i, ColdStart_Header, Resp_Buf );
2471 if ( Debug_Level > 1 && Log ) {
2473 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2476 close ( ilmi_fd[i] );