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
] );