Kernel tree reorganization stage 2: Major cvs repository work.
[dragonfly.git] / sbin / atm / ilmid / ilmid.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
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.
12  *
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.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sbin/atm/ilmid/ilmid.c,v 1.6.2.2 2001/03/04 07:15:30 kris Exp $
27  *      @(#) $DragonFly: src/sbin/atm/ilmid/ilmid.c,v 1.3 2003/08/08 04:18:37 dillon Exp $
28  */
29
30 /*
31  * User utilities
32  * --------------
33  *
34  * Implement very minimal ILMI address registration.
35  *
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.
42  *
43  * See "The Simple Book", Marshall T. Rose, particularly chapter 5,
44  * for ASN and BER information.
45  *
46  */
47
48 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <net/if.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>
64
65 #include <err.h>
66 #include <errno.h>
67 #include <libatm.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <syslog.h>
72 #include <time.h>
73 #include <unistd.h>
74
75 #define MAX_LEN         9180
76
77 #define MAX_UNITS       8
78
79 /*
80  * Define some ASN types
81  */
82 #define ASN_INTEGER     0x02
83 #define ASN_OCTET       0x04
84 #define ASN_NULL        0x05
85 #define ASN_OBJID       0x06
86 #define ASN_SEQUENCE    0x30
87 #define ASN_IPADDR      0x40
88 #define ASN_TIMESTAMP   0x43
89
90 static char *Var_Types[] = { "", "", "ASN_INTEGER", "", "ASN_OCTET", "ASN_NULL", "ASN_OBJID" };
91
92 /*
93  * Define SNMP PDU types
94  */
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
100
101 static char *PDU_Types[] = { "GET REQUEST", "GETNEXT REQUEST", "GET RESPONSE", "SET REQUEST",
102         "TRAP" };
103
104 /*
105  * Define TRAP codes
106  */
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
114
115 /*
116  * Define SNMP Version numbers
117  */
118 #define SNMP_VERSION_1  1
119 #define SNMP_VERSION_2  2
120
121 /*
122  * SNMP Error-status values
123  */
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
130
131 /*
132  * Max string length for Variable
133  */
134 #define STRLEN          128
135
136 /*
137  * Unknown variable
138  */
139 #define VAR_UNKNOWN     -1
140
141 /*
142  * Define our internal representation of an OBJECT IDENTIFIER
143  */
144 struct objid {
145         int     oid[128];
146 };
147 typedef struct objid Objid;
148
149 /*
150  * Define a Veriable classso that we can handle multiple GET/SET's
151  * per PDU.
152  */
153 typedef struct variable Variable;
154 struct variable {
155         Objid           oid;
156         int             type;
157         union {
158                 int             ival;           /* INTEGER/TIMESTAMP */
159                 Objid           oval;           /* OBJID */
160                 long            aval;           /* IPADDR */
161                 char            sval[STRLEN];   /* OCTET */
162         } var;
163         Variable        *next;
164 };
165
166 /*
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.
169  */
170 struct snmp_header {
171         int             pdulen;
172         int             version;
173         char            community[64];
174         int             pdutype;
175
176         /* GET/GETNEXT/GETRESP/SET */
177         int             reqid;
178         int             error;
179         int             erridx;
180
181         /* TRAP */
182         Objid           enterprise;
183         int             ipaddr;
184         int             generic_trap;
185         int             specific_trap;
186
187         int             varlen;
188         Variable        *head,
189                         *tail;
190 };
191 typedef struct snmp_header Snmp_Header;
192
193 Snmp_Header     *ColdStart_Header;
194 Snmp_Header     *PDU_Header;
195
196 /*
197  * Define some OBJET IDENTIFIERS that we'll try to reply to:
198  *
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
206  *                      switches...)
207  */
208 Objid   Objids[] = {
209 #define SYS_OBJID       0
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 }},
213 #define PORT_OBJID      2
214         {{ 12, 43, 6, 1, 4, 1,  353, 2, 1, 1, 1, 1, 0 }},
215 #define IPNM_OBJID      3
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 }},
231 #define MY_OBJID        11
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 }},
241 };
242
243 #define NUM_OIDS        (sizeof(Objids)/sizeof(Objid))
244
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
250
251 #define UNITYPE_PUBLIC  1
252 #define UNITYPE_PRIVATE 2
253
254 #define DEVTYPE_USER    1
255 #define DEVTYPE_NODE    2
256
257 /*
258  * ILMI protocol states
259  */
260 enum ilmi_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 */
266 };
267
268 /*
269  * Our (incrementing) Request ID
270  */
271 int     Req_ID;
272
273 /*
274  * Temporary buffer for building response packets. Should help ensure
275  * that we aren't accidently overwriting some other memory.
276  */
277 u_char  Resp_Buf[1024];
278
279 /*
280  * Copy the reponse into a buffer we can modify without
281  * changing the original...
282  */
283 #define COPY_RESP(resp) \
284         UM_COPY ( (resp), Resp_Buf, (resp)[0] + 1 )
285
286 /*
287  * TRAP generic trap types
288  */
289 char    *Traps[] = { "coldStart", "warmStart", "linkDown", "linkUp",
290                 "authenticationFailure", "egpNeighborLoss",
291                         "enterpriseSpecific" };
292
293
294 int                     NUnits;
295
296 /*
297  * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests
298  */
299 int                     ilmi_fd[MAX_UNITS + 1];
300 /*
301  * enum ilmi_states for this unit
302  */
303 int                     ilmi_state[MAX_UNITS + 1];
304 /*
305  * Local copy for HARP physical configuration information
306  */
307 struct air_cfg_rsp      Cfg[MAX_UNITS + 1];
308 /*
309  * Local copy for HARP interface configuration information
310  */
311 struct air_int_rsp      Intf[MAX_UNITS + 1];
312
313 /*
314  * addressEntry table
315  */
316 Objid                   addressEntry[MAX_UNITS + 1];
317
318 /*
319  * When this daemon started
320  */
321 struct timeval  starttime;
322
323 int     Debug_Level = 0;
324 int     foregnd = 0;    /* run in the foreground? */
325
326 char    *progname;
327 char    hostname[80];
328
329                                 /* File to write debug messages to */
330 #define LOG_FILE        "/var/log/ilmid"
331 FILE    *Log;                   /* File descriptor for log messages */
332
333 void    set_reqid __P ( ( u_char *, int ) );
334 void    Increment_DL __P ( ( int ) );
335 void    Decrement_DL __P ( ( int ) );
336
337 static char     *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
338                              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
339
340 /*
341  * Write a syslog() style timestamp
342  *
343  * Write a syslog() style timestamp with month, day, time and hostname
344  * to the log file.
345  *
346  * Arguments:
347  *      none
348  *
349  * Returns:
350  *      none
351  *
352  */
353 void
354 write_timestamp()
355 {
356         time_t          clock;
357         struct tm       *tm;
358
359         clock = time ( (time_t)NULL );
360         tm = localtime ( &clock );
361
362         if ( Log && Debug_Level > 1 )
363             if ( Log != stderr )
364                 fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
365                     Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
366                         tm->tm_sec, hostname );
367
368         return;
369
370 }
371
372 /*
373  * Utility to pretty print buffer as hex dumps
374  * 
375  * Arguments:
376  *      bp      - buffer pointer
377  *      len     - length to pretty print
378  *
379  * Returns:
380  *      none
381  *
382  */
383 void
384 hexdump ( bp, len )
385         u_char  *bp;
386         int     len;
387 {
388         int     i, j;
389
390         /*
391          * Print as 4 groups of four bytes. Each byte is separated
392          * by a space, each block of four is separated, and two blocks
393          * of eight are also separated.
394          */
395         for ( i = 0; i < len; i += 16 ) {
396                 if ( Log )
397                         write_timestamp();
398                 for ( j = 0; j < 4 && j + i < len; j++ )
399                     if ( Log )
400                         fprintf ( Log, "%.2x ", *bp++ );
401                 if ( Log )
402                     fprintf ( Log, " " );
403                 for ( ; j < 8 && j + i < len; j++ )
404                     if ( Log )
405                         fprintf ( Log, "%.2x ", *bp++ );
406                 if ( Log ) {
407                     fprintf ( Log, "  " );
408                     fflush ( Log );
409                 }
410                 for ( ; j < 12 && j + i < len; j++ )
411                     if ( Log )
412                         fprintf ( Log, "%.2x ", *bp++ );
413                 if ( Log )
414                     fprintf ( Log, " " );
415                 for ( ; j < 16 && j + i < len; j++ )
416                     if ( Log )
417                         fprintf ( Log, "%.2x ", *bp++ );
418                 if ( Log ) {
419                     fprintf ( Log, "\n" );
420                     fflush ( Log );
421                 }
422         }
423
424         return;
425
426 }
427
428 /*
429  * Get lengths from PDU encodings
430  *
431  * Lengths are sometimes encoded as a single byte if the length
432  * is less the 127 but are more commonly encoded as one byte with
433  * the high bit set and the lower seven bits indicating the nuber
434  * of bytes which make up the length value. Trailing data is (to my
435  * knowledge) not 7-bit encoded.
436  *
437  * Arguments:
438  *      bufp    - pointer to buffer pointer
439  *      plen    - pointer to PDU length or NULL if not a concern
440  *
441  * Returns: 
442  *      bufp    - updated buffer pointer
443  *      plen    - (possibly) adjusted pdu length
444  *      <len>   - decoded length
445  *
446  */
447 int
448 asn_get_pdu_len ( bufp, plen )
449         u_char  **bufp;
450         int     *plen;
451 {
452         u_char  *bp = *bufp;
453         int     len = 0;
454         int     i, b;
455
456         b = *bp++;
457         if ( plen )
458                 (*plen)--;
459          if ( b & 0x80 ) {
460                 for ( i = 0; i < (b & ~0x80); i++ ) {
461                         len = len * 256 + *bp++;
462                         if ( plen )
463                                 (*plen)--;
464                 }
465         } else
466                 len = b;
467
468         *bufp = bp;
469         return ( len );
470 }
471
472 /*
473  * Get an 7-bit encoded value.
474  *
475  * Get a value which is represented using a 7-bit encoding. The last
476  * byte in the stream has the high-bit clear.
477  *
478  * Arguments:
479  *      bufp    - pointer to the buffer pointer
480  *      len     - pointer to the buffer length
481  *
482  * Returns:
483  *      bufp    - updated buffer pointer
484  *      len     - updated buffer length
485  *      <val>   - value encoding represented
486  *
487  */
488 int
489 asn_get_encoded ( bufp, len )
490         u_char  **bufp;
491         int     *len;
492 {
493         u_char  *bp = *bufp;
494         int     val = 0;
495         int     l = *len;
496
497         /*
498          * Keep going while high bit is set
499          */
500         do {
501                 /*
502                  * Each byte can represent 7 bits
503                  */
504                 val = ( val << 7 ) + ( *bp & ~0x80 );
505                 l--;
506         } while ( *bp++ & 0x80 );
507
508         *bufp = bp;             /* update buffer pointer */
509         *len = l;               /* update buffer length */
510
511         return ( val );
512 }
513
514 /*
515  * Get a BER encoded integer
516  *
517  * Intergers are encoded as one byte length followed by <length> data bytes
518  *
519  * Arguments:
520  *      bufp    - pointer to the buffer pointer
521  *      plen    - pointer to PDU length or NULL if not a concern
522  *
523  * Returns:
524  *      bufp    - updated buffer pointer 
525  *      plen    - (possibly) updated PDU length
526  *      <val>   - value of encoded integer
527  *
528  */
529 int
530 asn_get_int ( bufp, plen )
531         u_char  **bufp;
532         int     *plen;
533 {
534         int     i;
535         int     len;
536         int     v = 0;
537         u_char  *bp = *bufp;
538
539         len = *bp++;
540         if ( plen )
541                 (*plen)--;
542         for ( i = 0; i < len; i++ ) {
543                 v = (v * 256) + *bp++;
544                 if ( plen )
545                         (*plen)--;
546         }
547         *bufp = bp;
548         return ( v );
549 }
550
551 /*
552  * Set a BER encoded integer
553  *
554  * Arguments:
555  *      bufp    - pointer to buffer pointer where we are to set int in
556  *      val     - integer value to set
557  *
558  * Returns:
559  *      none
560  *      <bufp>  - updated buffer pointer
561  *
562  */
563 void
564 asn_set_int ( bufp, val )
565         u_char  **bufp;
566         int     val;
567 {
568         union {
569                 int     i;
570                 u_char  c[4];
571         } u;
572         int     len = sizeof(int);
573         int     i = 0;
574         u_char  *bp = *bufp;
575
576         /* Check for special case where val == 0 */
577         if ( val == 0 ) {
578                 *bp++ = 1;
579                 *bp++ = 0;
580                 *bufp = bp;
581                 return;
582         }
583
584         u.i = htonl ( val );
585
586         while ( u.c[i] == 0  && i++ < sizeof(int) )
587                 len--;
588
589         if ( u.c[i] > 0x7f ) {
590                 i--;
591                 len++;
592         }
593
594         *bp++ = len;
595         UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
596         bp += len;
597         *bufp = bp;
598
599         return;
600 }
601
602 /*
603  * Utility to print a object identifier
604  *
605  * Arguments:
606  *      objid   - pointer to objid representation
607  *
608  * Returns:
609  *      none
610  *
611  */
612 void
613 print_objid ( objid )
614         Objid   *objid;
615 {
616         int     i;
617
618         /*
619          * First oid coded as 40 * X + Y
620          */
621         if ( Log ) {
622             write_timestamp();
623             fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
624                 objid->oid[1] % 40 );
625         }
626         for ( i = 2; i <= objid->oid[0]; i++ )
627             if ( Log )
628                 fprintf ( Log, ".%d", objid->oid[i] );
629         if ( Log )
630             fprintf ( Log, "\n" );
631
632         return;
633 }
634
635 /*
636  * Get Object Identifier
637  *
638  * Arguments:
639  *      bufp    - pointer to buffer pointer
640  *      objid   - pointer to objid buffer
641  *      plen    - pointer to PDU length or NULL of not a concern
642  *
643  * Returns:
644  *      bufp    - updated buffer pointer
645  *      objid   - internal representation of encoded objid
646  *      plen    - (possibly) adjusted PDU length
647  *
648  */
649 void
650 asn_get_objid ( bufp, objid, plen )
651         u_char  **bufp;
652         Objid   *objid;
653         int     *plen;
654 {
655         int     len;
656         u_char  *bp = *bufp;
657         int     *ip = (int *)objid + 1; /* First byte will contain length */
658         int     oidlen = 0;
659
660         len = *bp++;
661         if ( plen )
662                 (*plen)--;
663         while ( len ) {
664                 *ip++ = asn_get_encoded ( &bp, &len );
665                 if ( plen )
666                         (*plen)--;
667                 oidlen++;
668         }
669         objid->oid[0] = oidlen;
670         *bufp = bp;
671
672         return;
673 }
674
675 /*
676  * Put OBJID - assumes elements <= 16383 for two byte coding
677  *
678  */
679 int
680 asn_put_objid ( bufp, objid )
681         u_char  **bufp;
682         Objid   *objid;
683 {
684         int     len = 0;
685         u_char  *bp = *bufp;
686         u_char  *cpp;
687         int     i;
688
689         cpp = bp;
690         *bp++ = objid->oid[0];
691         len++;
692         for ( i = 1; i <= objid->oid[0]; i++ ) {
693                 u_int   c = objid->oid[i];
694
695                 while ( c > 127 ) {
696                         *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
697                         len++;
698                         c &= 0x7f;              /* XXX - assumption of two bytes */
699                         (*cpp)++;
700                 }
701                 *bp++ = c;
702                 len++;
703         }
704
705         *bufp = bp;
706         return ( len );
707
708 }
709
710 /*
711  * Get OCTET STRING
712  *
713  * Octet strings are encoded as a 7-bit encoded length followed by <len>
714  * data bytes;
715  *
716  * Arguments:
717  *      bufp    - pointer to buffer pointer
718  *      octet   - pointer to octet buffer
719  *      plen    - pointer to PDU length
720  *
721  * Returns:
722  *      bufp    - updated buffer pointer
723  *      octet   - encoded Octet String
724  *      plen    - (possibly) adjusted PDU length
725  *
726  */ 
727 void
728 asn_get_octet ( bufp, octet, plen )
729         u_char  **bufp;
730         char    *octet;
731         int     *plen;
732 {
733         u_char  *bp = *bufp;
734         int     i = 0;
735         int     len = 0;
736
737         /*
738          * &i is really a dummy value here as we don't keep track
739          * of the ongoing buffer length
740          */
741         len = asn_get_encoded ( &bp, &i, plen );
742
743         for ( i = 0; i < len; i++ ) {
744                 *octet++ = *bp++;
745                 if ( plen )
746                         (*plen)--;
747         }
748
749         *bufp = bp;
750
751         return;
752
753 }
754
755 /*
756  * Utility to print SNMP PDU header information
757  *
758  * Arguments:
759  *      Hdr     - pointer to internal SNMP header structure
760  *
761  * Returns:
762  *      none
763  *
764  */
765 void
766 print_header ( Hdr )
767         Snmp_Header *Hdr;
768 {
769         Variable        *var;
770
771         if ( Log ) {
772             write_timestamp();
773             fprintf ( Log,
774                 "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x %s\n",
775                     Hdr->pdulen, Hdr->version + 1, Hdr->community,
776                         Hdr->pdutype, PDU_Types[Hdr->pdutype - PDU_TYPE_GET] );
777             write_timestamp();
778             if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
779                 fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
780                     Hdr->reqid, Hdr->error, Hdr->erridx );
781         }
782
783         var = Hdr->head;
784         while ( var ) {
785                 if ( Log ) {
786                         write_timestamp();
787                         fprintf ( Log, "    Variable Type: %d", var->type );
788                         if ( Var_Types[var->type] )
789                                 fprintf ( Log, " %s", Var_Types[var->type] );
790                         fprintf ( Log, "\n\tObject: " );
791                         print_objid ( &var->oid );
792                         fprintf ( Log, "\tValue: " );
793                         switch ( var->type ) {
794                         case ASN_INTEGER:
795                                 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
796                                 break;
797                         case ASN_NULL:
798                                 fprintf ( Log, "NULL" );
799                                 break;
800                         default:
801                                 fprintf ( Log, "[0x%x]", var->type );
802                                 break;
803                         }
804                         fprintf ( Log, "\n" );
805                 }
806                 var = var->next;
807         }
808
809         return;
810
811 }
812
813 /*
814  * Pull OID's from GET/SET message
815  *
816  * Arguments:
817  *      h       - pointer to Snmp_Header
818  *      bp      - pointer to input PDU
819  *
820  * Returns:
821  *      none
822  *
823  */
824 void
825 parse_oids ( h, bp )
826         Snmp_Header     *h;
827         caddr_t         *bp;
828 {
829         int             len = h->varlen;
830         int             sublen;
831         Variable        *var;
832         caddr_t         bufp = *bp;
833
834         while ( len > 0 ) {
835             if ( *bufp++ == ASN_SEQUENCE ) {
836                 len--;
837
838                 /* Create new Variable instance */
839                 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
840                 {
841                         *bp = bufp;
842                         return;
843                 }
844                 /* Link to tail */
845                 if ( h->tail )
846                         h->tail->next = var;
847                 /* Set head iff NULL */
848                 if ( h->head == NULL ) {
849                         h->head = var;
850                 }
851                 /* Adjust tail */
852                 h->tail = var;
853
854                 /* Get length of variable sequence */
855                 sublen = asn_get_pdu_len ( &bufp, &len );
856                 /* Should be OBJID type */
857                 if ( *bufp++ != ASN_OBJID ) {
858                         *bp = bufp;
859                         return;
860                 }
861                 asn_get_objid ( &bufp, &var->oid, &len );
862                 var->type = *bufp++;
863                 len--;
864                 switch ( var->type ) {
865                 case ASN_INTEGER:
866                         var->var.ival = asn_get_int ( &bufp, &len );
867                         break;
868                 case ASN_NULL:
869                         bufp++;
870                         len--;
871                         break;
872                 case ASN_OBJID:
873                         asn_get_objid ( &bufp, &var->var.oval, &len );
874                         break;
875                 case ASN_OCTET:
876                         asn_get_octet ( &bufp, var->var.sval, &len );
877                         break;
878                 default:
879                         if ( Log ) {
880                                 write_timestamp();
881                                 fprintf ( Log, "Unknown variable type: %d\n",
882                                         var->type );
883                         }
884                         break;
885                 }
886                 var->next = NULL;
887             } else
888                 break;
889         }
890
891         *bp = bufp;
892         return;
893 }
894
895 /*
896  * Crack the SNMP header
897  *
898  * Pull the PDU length, SNMP version, SNMP community and PDU type.
899  * If present, also pull out the Request ID, Error status, and Error
900  * index values.
901  *
902  * Arguments:
903  *      bufp    - pointer to buffer pointer
904  *
905  * Returns:
906  *      bufp    - updated buffer pointer
907  *              - generated SNMP header
908  *
909  */
910 Snmp_Header *
911 asn_get_header ( bufp )
912         u_char **bufp;
913 {
914         Snmp_Header     *h;
915         u_char          *bp = *bufp;
916         int             len = 0;
917         int             dummy = 0;
918
919         /*
920          * Allocate memory to hold the SNMP header
921          */
922         if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
923                 return ( (Snmp_Header *)NULL );
924
925         /*
926          * Ensure that we wipe the slate clean
927          */
928         UM_ZERO ( h, sizeof ( Snmp_Header ) );
929
930         /*
931          * PDU has to start as SEQUENCE OF
932          */
933         if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
934                 return ( (Snmp_Header *)NULL );
935
936         /*
937          * Get the length of remaining PDU data
938          */
939         h->pdulen = asn_get_pdu_len ( &bp, NULL );
940
941         /*
942          * We expect to find an integer encoding Version-1
943          */
944         if ( *bp++ != ASN_INTEGER ) {
945                 return ( (Snmp_Header *)NULL );
946         }
947         h->version = asn_get_int ( &bp, NULL );
948
949         /*
950          * After the version, we need the community name
951          */
952         if ( *bp++ != ASN_OCTET ) {
953                 return ( (Snmp_Header *)NULL );
954         }
955         asn_get_octet ( &bp, h->community, NULL );
956
957         /*
958          * Single byte PDU type
959          */
960         h->pdutype = *bp++;
961
962         /*
963          * If this isn't a TRAP PDU, then look for the rest of the header
964          */
965         if ( h->pdutype != PDU_TYPE_TRAP ) {    /* TRAP uses different format */
966
967                 (void) asn_get_pdu_len ( &bp, &dummy );
968
969                 /* Request ID */
970                 if ( *bp++ != ASN_INTEGER ) {
971                         UM_FREE ( h );
972                         return ( (Snmp_Header *)NULL );
973                 }
974                 h->reqid = asn_get_int ( &bp, NULL );
975
976                 /* Error Status */
977                 if ( *bp++ != ASN_INTEGER ) {
978                         UM_FREE ( h );
979                         return ( (Snmp_Header *)NULL );
980                 }
981                 h->error = asn_get_int ( &bp, NULL );
982
983                 /* Error Index */
984                 if ( *bp++ != ASN_INTEGER ) {
985                         UM_FREE ( h );
986                         return ( (Snmp_Header *)NULL );
987                 }
988                 h->erridx = asn_get_int ( &bp, NULL );
989
990                 /* Sequence of... */
991                 if ( *bp++ != ASN_SEQUENCE ) {
992                         UM_FREE ( h );
993                         return ( (Snmp_Header *)NULL );
994                 }
995                 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
996                 h->varlen += ( len - 1 );
997
998                 parse_oids ( h, &bp );
999         }
1000
1001         *bufp = bp;
1002
1003         if ( Log && Debug_Level )
1004                 print_header ( h );
1005
1006         return ( h );
1007
1008 }
1009
1010 /*
1011  * Compare two internal OID representations
1012  *
1013  * Arguments:
1014  *      oid1    - Internal Object Identifier
1015  *      oid2    - Internal Object Identifier
1016  *
1017  * Returns:
1018  *      0       - Objid's match
1019  *      1       - Objid's don't match
1020  *
1021  */
1022 int
1023 oid_cmp ( oid1, oid2 )
1024         Objid *oid1, *oid2;
1025 {
1026         int     i;
1027         int     len;
1028
1029         /*
1030          * Compare lengths
1031          */
1032         if ( !(oid1->oid[0] == oid2->oid[0] ) )
1033                 /* Different lengths */
1034                 return ( 1 );
1035
1036         len = oid1->oid[0];
1037
1038         /*
1039          * value by value compare
1040          */
1041         for ( i = 1; i <= len; i++ ) {
1042                 if ( !(oid1->oid[i] == oid2->oid[i]) )
1043                         /* values don't match */
1044                         return ( 1 );
1045         }
1046
1047         /* Objid's are identical */
1048         return ( 0 );
1049 }
1050
1051 /*
1052  * Compare two internal OID representations
1053  *
1054  * Arguments:
1055  *      oid1    - Internal Object Identifier
1056  *      oid2    - Internal Object Identifier
1057  *      len     - Length of OID to compare
1058  *
1059  * Returns:
1060  *      0       - Objid's match
1061  *      1       - Objid's don't match
1062  *
1063  */
1064 int
1065 oid_ncmp ( oid1, oid2, len )
1066         Objid *oid1, *oid2;
1067         int     len;
1068 {
1069         int     i;
1070
1071         /*
1072          * value by value compare
1073          */
1074         for ( i = 1; i <= len; i++ ) {
1075                 if ( !(oid1->oid[i] == oid2->oid[i]) )
1076                         /* values don't match */
1077                         return ( 1 );
1078         }
1079
1080         /* Objid's are identical */
1081         return ( 0 );
1082 }
1083
1084 /*
1085  * Find the index of a OBJID which matches this Variable instance 
1086  *
1087  * Arguments:
1088  *      var     - pointer to Variable instance
1089  *
1090  * Returns:
1091  *      idx     - index of matched Variable instance
1092  *      -1      - no matching Variable found
1093  *
1094  */
1095 int
1096 find_var ( var )
1097         Variable        *var;
1098 {
1099         int     i;
1100
1101         for ( i = 0; i < NUM_OIDS; i++ )
1102                 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1103                         return ( i );
1104                 }
1105
1106         return ( -1 );
1107
1108 }
1109
1110 /*
1111  * Return the time process has been running as a number of ticks 
1112  *
1113  * Arguments:
1114  *      none
1115  *
1116  * Returns:
1117  *      number of ticks
1118  *
1119  */
1120 int
1121 get_ticks()
1122 {
1123         struct timeval  timenow;
1124         struct timeval  timediff;
1125
1126         (void) gettimeofday ( &timenow, NULL );
1127         /*
1128          * Adjust for subtraction
1129          */
1130         timenow.tv_sec--;
1131         timenow.tv_usec += 1000000;
1132
1133         /*
1134          * Compute time since 'starttime'
1135          */
1136         timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1137         timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1138
1139         /*
1140          * Adjust difference timeval
1141          */
1142         if ( timediff.tv_usec >= 1000000 ) {
1143                 timediff.tv_usec -= 1000000;
1144                 timediff.tv_sec++;
1145         }
1146
1147         /*
1148          * Compute number of ticks
1149          */
1150         return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1151
1152 }
1153
1154 /*
1155  * Build a response PDU
1156  *
1157  * Arguments:
1158  *      hdr     - pointer to PDU Header with completed Variable list
1159  *
1160  * Returns:
1161  *      none
1162  *
1163  */
1164 void
1165 build_pdu ( hdr, type )
1166         Snmp_Header     *hdr;
1167         int             type;
1168 {
1169         u_char          *bp = Resp_Buf;
1170         u_char          *vpp;
1171         u_char          *ppp;
1172         int             erridx = 0;
1173         int             varidx = 1;
1174         int             varlen = 0;
1175         int             pdulen = 0;
1176         int             traplen = 0;
1177         Variable        *var;
1178
1179         /*
1180          * Clear out the reply
1181          */
1182         UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1183
1184         /* [0] is reserved for overall length */
1185         bp++;
1186
1187         /* Start with SEQUENCE OF */
1188         *bp++ = ASN_SEQUENCE;
1189         /* - assume we can code length in two octets */
1190         *bp++ = 0x82;
1191         bp++;
1192         bp++;
1193         /* Version */
1194         *bp++ = ASN_INTEGER;
1195         asn_set_int ( &bp, hdr->version );
1196         /* Community name */
1197         *bp++ = ASN_OCTET;
1198         *bp++ = strlen ( hdr->community );
1199         UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1200         bp += strlen ( hdr->community );
1201         /* PDU Type */
1202         *bp++ = type;
1203         ppp = bp;
1204         /* Length of OID data - assume it'll fit in one octet */
1205         bp++;
1206
1207         if ( type != PDU_TYPE_TRAP ) {
1208             /* Sequence ID */
1209             *bp++ = ASN_INTEGER;
1210             asn_set_int ( &bp, hdr->reqid );
1211             /*
1212              * Check to see if all the vaiables were resolved - we do this
1213              * by looking for something which still has a ASN_NULL value.
1214              */
1215             var = hdr->head;
1216             if ( type == PDU_TYPE_GETRESP ) {
1217                 while ( var && erridx == 0 ) {
1218                     if ( var->type != ASN_NULL ) {
1219                             varidx++;
1220                             var = var->next;
1221                     } else
1222                         erridx = varidx;
1223                 }
1224             }
1225
1226             /* Error status */
1227             *bp++ = ASN_INTEGER;
1228             *bp++ = 0x01;       /* length = 1 */
1229             if ( erridx )
1230                 *bp++ = SNMP_ERR_NOSUCHNAME;
1231             else
1232                 *bp++ = SNMP_ERR_NOERROR;
1233             /* Error Index */
1234             *bp++ = ASN_INTEGER;
1235             *bp++ = 0x01;       /* length = 1 */
1236             *bp++ = erridx;     /* index - 0 if no error */
1237         } else {
1238                 /* type == PDU_TYPE_TRAP */
1239
1240                 /* Fill in ENTERPRISE OBJID */
1241                 *bp++ = ASN_OBJID;
1242                 (void) asn_put_objid ( &bp, &hdr->enterprise );
1243
1244                 /* Fill in IP address */
1245                 *bp++ = ASN_IPADDR;
1246                 *bp++ = sizeof ( hdr->ipaddr );
1247                 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1248                 bp += sizeof(hdr->ipaddr);
1249
1250                 /* Fill in generic and specific trap types */
1251                 *bp++ = ASN_INTEGER;
1252                 asn_set_int ( &bp, hdr->generic_trap );
1253                 *bp++ = ASN_INTEGER;
1254                 asn_set_int ( &bp, hdr->specific_trap );
1255
1256                 /* Fill in time-stamp  - assume 0 for now */
1257                 *bp++ = ASN_TIMESTAMP;
1258                 asn_set_int ( &bp, 0 );
1259                 
1260                 /* encoded length */
1261                 traplen = ( bp - ppp - 1 );
1262
1263                 /* Continue with variable processing */
1264         }
1265
1266         /* SEQUENCE OF */
1267         *bp++ = ASN_SEQUENCE;
1268         *bp++ = 0x82;
1269         /* - assume we can code length in two octets */
1270         vpp = bp;
1271         varlen = 0;
1272         bp++;
1273         bp++;
1274
1275         /* Install Variables */
1276         var = hdr->head;
1277         varidx = 1;
1278         while ( var ) {
1279                 u_char *bpp;
1280                 int     len = 0;
1281
1282                 /* SEQUENCE OF */
1283                 *bp++ = ASN_SEQUENCE;
1284                 *bp++ = 0x82;
1285                 /* - assume we can code length in two octets */
1286                 bpp = bp;
1287                 bp++;
1288                 bp++;
1289                 /* OBJID */
1290                 *bp++ = ASN_OBJID;
1291                 len++;
1292                 len += asn_put_objid ( &bp, &var->oid );
1293
1294                 if ( erridx && varidx >= erridx ) {
1295                         /* Code this variable as NULL */
1296                         *bp++ = ASN_NULL;
1297                         len++;
1298                         bp++;
1299                         len++;
1300                 } else {
1301                         u_char *lpp;
1302                         /* Variable type */
1303                         *bp++ = var->type;
1304                         len++;
1305                         lpp = bp;
1306                         switch ( var->type ) {
1307                         case ASN_INTEGER:
1308                                 asn_set_int ( &bp, var->var.ival );
1309                                 len += ( *lpp + 1 );
1310                                 break;
1311                         case ASN_OCTET:
1312                                 *bp++ = var->var.sval[0];
1313                                 len++;
1314                                 UM_COPY ( (caddr_t)&var->var.sval[1],
1315                                         bp, var->var.sval[0] );
1316                                 len += var->var.sval[0];
1317                                 bp += var->var.sval[0];
1318                                 break;
1319                         case ASN_NULL:
1320                                 *bp++ = 0x00;
1321                                 len++;
1322                                 break;
1323                         case ASN_OBJID:
1324                                 len += asn_put_objid ( &bp, &var->var.oval );
1325                                 break;
1326                         case ASN_SEQUENCE:
1327                                 break;
1328                         case ASN_IPADDR:
1329                                 *bp++ = 4;
1330                                 len++;
1331                                 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1332                                 len += 4;
1333                                 bp += 4;
1334                                 break;
1335                         case ASN_TIMESTAMP:
1336                                 asn_set_int ( &bp, var->var.ival );
1337                                 len += ( *lpp + 1 );
1338                                 break;
1339                         default:
1340                                 break;
1341                         }
1342                 }
1343
1344                 /* Accumulate total Variable sequence length */
1345                 varlen += (len + 4);
1346
1347                 /* Fill in length of this sequence */
1348                 bpp[1] = len & 0xff;
1349                 bpp[0] = len >> 8;
1350
1351                 var = var->next;
1352         }
1353
1354
1355         /* Fill in length of Variable sequence */
1356         vpp[1] = varlen & 0xff;
1357         vpp[0] = varlen >> 8;
1358
1359         if ( type != PDU_TYPE_TRAP ) {
1360                 /* Fill in length of data AFTER PDU type */
1361                 *ppp = varlen + 12 + ppp[2];    /* + length of reqid */
1362         } else {
1363                 /* Fill in length of data AFTER PDU  type */
1364                 *ppp = varlen + traplen + 4;    /* + length of initial sequence of */
1365         }
1366
1367         /* Fill in overall sequence length */
1368         pdulen = *ppp + 7 + strlen ( hdr->community );
1369         Resp_Buf[4] = pdulen & 0x7f;
1370         Resp_Buf[3] = pdulen >> 8;
1371
1372         pdulen = bp - Resp_Buf - 1;
1373
1374         Resp_Buf[0] = pdulen;
1375
1376         hdr->pdutype = type;
1377
1378         return;
1379 }
1380
1381 void
1382 free_pdu ( hdr )
1383 Snmp_Header *hdr;
1384 {
1385         Variable        *var;
1386
1387         while ( hdr->head ) {
1388                 var = hdr->head->next;          /* Save next link */
1389                 UM_FREE ( hdr->head );          /* Free current var */
1390                 hdr->head = var;                /* Set head to next link */
1391         }
1392
1393         UM_FREE ( hdr );                                /* Free fixed portion */
1394 }
1395
1396 /*
1397  * Set Request ID in PDU
1398  *
1399  * Arguments:
1400  *      resp    - Response PDU buffer
1401  *      reqid   - request id value
1402  *
1403  * Returns:
1404  *      none    - request id may/may not be set
1405  *
1406  */
1407 void
1408 set_reqid ( resp, reqid )
1409         u_char  *resp;
1410         int     reqid;
1411 {
1412         u_char          *bp = (u_char *)&resp[18];
1413         union {
1414                 int     i;
1415                 u_char  c[4];
1416         } u;    
1417
1418         u.i = htonl(reqid);
1419
1420         /*
1421          * Replace the current Request ID with the supplied value
1422          */
1423         UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1424
1425         return;
1426 }
1427
1428 /*
1429  * Send a generic response packet
1430  *
1431  * Arguments:
1432  *      sd      - socket to send the reply on
1433  *      reqid   - original request ID from GET PDU
1434  *      resp    - pointer to the response to send
1435  *
1436  * Returns:
1437  *      none    - response sent
1438  *
1439  */
1440 void
1441 send_resp ( intf, Hdr, resp )
1442         int             intf;
1443         Snmp_Header     *Hdr;
1444         u_char          *resp;
1445 {
1446         int     n;
1447
1448         if ( ilmi_fd[intf] > 0 ) {
1449             n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1450             if ( Log && Debug_Level > 1 ) {
1451                 write_timestamp();
1452                 fprintf ( Log, "===== Sent %d of %d bytes (%d) =====\n", n, resp[0], ilmi_fd[intf] );
1453                 print_header ( Hdr );
1454                 if ( Debug_Level > 2 )
1455                         hexdump ( (u_char *)&resp[1], resp[0] );
1456             }
1457         }
1458
1459         free_pdu ( Hdr );
1460         return;
1461 }
1462
1463 /*
1464  * Build a COLD_START TRAP PDU
1465  *
1466  */
1467 Snmp_Header *
1468 build_cold_start()
1469 {
1470         Snmp_Header     *hdr;
1471         Variable        *var;
1472
1473         hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1474
1475         hdr->pdulen = 0;
1476         hdr->version = SNMP_VERSION_1 - 1;
1477         snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1478
1479         hdr->ipaddr = 0x0;      /* 0.0.0.0 */
1480         hdr->generic_trap = TRAP_COLDSTART;
1481         hdr->specific_trap = 0;
1482         UM_COPY ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1483                 sizeof(Objid) );
1484
1485         hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1486         var = hdr->head;
1487         UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1488                 sizeof(Objid) );
1489         var->type = ASN_NULL;
1490
1491         return ( hdr );
1492 }
1493
1494 /*
1495  * Build a Generic PDU Header
1496  *
1497  */
1498 Snmp_Header *
1499 build_generic_header()
1500 {
1501         Snmp_Header     *hdr;
1502
1503         hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1504
1505         hdr->pdulen = 0;
1506         hdr->version = SNMP_VERSION_1 - 1;
1507         snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1508
1509         return ( hdr );
1510 }
1511
1512 /* 
1513  * Initialize information on what physical adapters HARP knows about
1514  *
1515  * Query the HARP subsystem about configuration and physical interface
1516  * information for any currently registered ATM adapters. Store the information
1517  * as arrays for easier indexing by SNMP port/index numbers.
1518  *      
1519  * Arguments:
1520  *      none
1521  *
1522  * Returns:
1523  *      none            Information from HARP available 
1524  *      
1525  */
1526 void    
1527 init_ilmi()  
1528 {
1529         struct  air_cfg_rsp     *cfg_info = NULL;
1530         struct  air_int_rsp    *intf_info = NULL;
1531         int                     buf_len;
1532
1533         /*
1534          * Get configuration info - what's available with 'atm sh config'
1535          */
1536         buf_len = get_cfg_info ( NULL, &cfg_info );
1537         /*
1538          * If error occurred, clear out everything
1539          */
1540         if ( buf_len <= 0 ) {
1541                 UM_ZERO ( Cfg, sizeof(Cfg) );
1542                 UM_ZERO ( Intf, sizeof(Intf) );
1543                 NUnits = 0;
1544                 return;
1545         }
1546
1547         /*
1548          * Move to local storage
1549          */
1550         UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1551         /*
1552          * Compute how many units information was returned for
1553          */
1554         NUnits = buf_len / sizeof(struct air_cfg_rsp);
1555         /* Housecleaning */
1556         UM_FREE ( cfg_info );
1557         cfg_info = NULL;
1558         /*
1559          * Get the per interface information
1560          */
1561         buf_len = get_intf_info ( NULL, &intf_info );
1562         /*
1563          * If error occurred, clear out Intf info
1564          */
1565         if ( buf_len <= 0 ) {
1566                 UM_ZERO ( Intf, sizeof(Intf) );
1567                 return;
1568         }
1569
1570         /*
1571          * Move to local storage
1572          */
1573         UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1574         /* Housecleaning */
1575         UM_FREE ( intf_info );
1576         intf_info = NULL;
1577
1578         return;
1579
1580 }
1581
1582 /*
1583  * Open a new SNMP session for ILMI
1584  *
1585  * Start by updating interface information, in particular, how many
1586  * interfaces are in the system. While we'll try to open sessons on
1587  * all interfaces, this deamon currently can only handle the first
1588  * interface.
1589  *
1590  * Arguments:
1591  *      none
1592  *
1593  * Returns:
1594  *      none
1595  *
1596  */
1597 void
1598 ilmi_open ()
1599 {
1600         struct sockaddr_atm     satm;
1601         struct t_atm_aal5       aal5;
1602         struct t_atm_traffic    traffic;
1603         struct t_atm_bearer     bearer;
1604         struct t_atm_qos        qos;
1605         struct t_atm_app_name   appname;
1606         Atm_addr                subaddr;
1607         char                    nifname[IFNAMSIZ];
1608         int                     optlen;
1609         int                     unit = 0;
1610         u_char                  sig_proto;
1611
1612         init_ilmi();
1613
1614         for ( unit = 0; unit < NUnits; unit++ ) {
1615
1616             /*
1617              * ILMI only makes sense for UNI signalling protocols
1618              */
1619             sig_proto = Intf[unit].anp_sig_proto;
1620             if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1621                 sig_proto != ATM_SIG_UNI40 )
1622                     continue;
1623
1624             if ( ilmi_fd[unit] == -1 ) {
1625
1626                 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1627
1628                 if ( ilmi_fd[unit] < 0 ) {
1629                     perror ( "open" );
1630                     continue;
1631                 }
1632
1633                 /*
1634                  * Set interface name. For now, we must have a netif to go on...
1635                  */
1636                 if ( Intf[unit].anp_nif_cnt == 0 ) {
1637                     if ( Debug_Level > 1 && Log ) {
1638                         write_timestamp();
1639                         fprintf ( Log, "No nif on unit %d\n", unit );
1640                     }
1641                     close ( ilmi_fd[unit] );
1642                     ilmi_fd[unit] = -1;
1643                     continue;
1644                 }
1645                 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1646                 optlen = sizeof ( nifname );
1647                 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1648                     T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1649                         perror ( "setsockopt" );
1650                         if ( Log ) {
1651                             write_timestamp();
1652                             fprintf ( Log,
1653                                 "Couldn't set interface name \"%s\"\n",
1654                                     nifname );
1655                         }
1656                         if ( Debug_Level > 1 && Log ) {
1657                             write_timestamp();
1658                             fprintf ( Log, "nifname: closing unit %d\n", unit );
1659                         }
1660                         close ( ilmi_fd[unit] );
1661                         ilmi_fd[unit] = -1;
1662                         continue;
1663                 }
1664
1665                 /*
1666                  * Set up destination SAP
1667                  */
1668                 UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
1669                 satm.satm_family = AF_ATM;
1670 #if (defined(BSD) && (BSD >= 199103))
1671                 satm.satm_len = sizeof(satm);
1672 #endif
1673
1674                 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1675                 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1676                 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1677                 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1678                 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1679                     0 );
1680                 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1681                     16 );
1682     
1683                 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1684                 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1685                 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1686
1687                 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1688
1689                 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1690
1691                 /*
1692                  * Set up connection parameters
1693                  */
1694                 aal5.forward_max_SDU_size = MAX_LEN;
1695                 aal5.backward_max_SDU_size = MAX_LEN;
1696                 aal5.SSCS_type = T_ATM_NULL;
1697                 optlen = sizeof(aal5);
1698                 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1699                 (caddr_t) &aal5, optlen ) < 0 ) {
1700                     perror ( "setsockopt(aal5)" );
1701                     if ( Debug_Level > 1 && Log ) {
1702                         write_timestamp();
1703                         fprintf ( Log, "aal5: closing unit %d\n", unit );
1704                     }
1705                     close ( ilmi_fd[unit] );
1706                     ilmi_fd[unit] = -1;
1707                     continue;
1708                 }
1709
1710                 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1711                 traffic.forward.PCR_all_traffic = 100000;
1712                 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1713                 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1714                 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1715                 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1716                 traffic.forward.tagging = T_NO;
1717                 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1718                 traffic.backward.PCR_all_traffic = 100000;
1719                 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1720                 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1721                 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1722                 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1723                 traffic.backward.tagging = T_NO;
1724                 traffic.best_effort = T_YES;
1725                 optlen = sizeof(traffic);
1726                 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1727                         (caddr_t)&traffic, optlen) < 0) {
1728                     perror("setsockopt(traffic)");
1729                 }
1730                 bearer.bearer_class = T_ATM_CLASS_X;
1731                 bearer.traffic_type = T_ATM_NULL;
1732                 bearer.timing_requirements = T_ATM_NULL;
1733                 bearer.clipping_susceptibility = T_NO;
1734                 bearer.connection_configuration = T_ATM_1_TO_1;
1735                 optlen = sizeof(bearer);
1736                 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1737                         (caddr_t)&bearer, optlen) < 0) {
1738                     perror("setsockopt(bearer)");
1739                 }
1740
1741                 qos.coding_standard = T_ATM_NETWORK_CODING;
1742                 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1743                 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1744                 optlen = sizeof(qos);
1745                 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1746                         optlen) < 0) {
1747                     perror("setsockopt(qos)");
1748                 }
1749
1750                 subaddr.address_format = T_ATM_ABSENT;
1751                 subaddr.address_length = 0;
1752                 optlen = sizeof(subaddr);
1753                 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1754                         (caddr_t)&subaddr, optlen) < 0) {
1755                     perror("setsockopt(dest_sub)");
1756                 }
1757
1758                 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1759                 optlen = sizeof(appname);
1760                 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1761                         (caddr_t)&appname, optlen) < 0) {
1762                     perror("setsockopt(appname)");
1763                 }
1764
1765                 /*
1766                  * Now try to connect to destination
1767                  */
1768                 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1769                     sizeof(satm)) < 0 ) {
1770                         perror ( "connect" );
1771                         if ( Debug_Level > 1 && Log ) {
1772                             write_timestamp();
1773                             fprintf ( Log, "connect: closing unit %d\n", unit );
1774                         }
1775                         close ( ilmi_fd[unit] );
1776                         ilmi_fd[unit] = -1;
1777                         continue;
1778                 }
1779
1780                 if ( Debug_Level && Log ) {
1781                     write_timestamp();
1782                     fprintf ( Log, "***** opened unit %d\n", unit );
1783                 }
1784
1785                 ilmi_state[unit] = ILMI_COLDSTART;
1786
1787             }
1788
1789         }
1790
1791         return;
1792
1793 }
1794
1795 /*
1796  * Get our local IP address for this interface
1797  *
1798  * Arguments:
1799  *      s       - socket to find address for
1800  *      aval    - pointer to variable to store address in
1801  *
1802  * Returns:
1803  *      none
1804  *
1805  */
1806 void
1807 get_local_ip ( s, aval )
1808         int     s;
1809         long    *aval;
1810 {
1811         char                    intf_name[IFNAMSIZ];
1812         int                     namelen = IFNAMSIZ;
1813         struct air_netif_rsp    *net_info = NULL;
1814         struct sockaddr_in      *sin;
1815
1816         /*
1817          * Get physical interface name
1818          */
1819         if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1820             (caddr_t) intf_name, &namelen ) )
1821                 return;
1822
1823         /*
1824          * Get network interface information for this physical interface
1825          */
1826         get_netif_info ( intf_name, &net_info );
1827         if ( net_info == NULL )
1828                 return;
1829
1830         sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1831
1832         /*
1833          * Fill in answer
1834          */
1835         UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1836
1837         UM_FREE ( net_info );
1838
1839         return;
1840
1841 }
1842
1843 /*
1844  * Set local NSAP prefix and then reply with our full NSAP address.
1845  *
1846  * Switch will send a SET message with the NSAP prefix after a coldStart.
1847  * We'll set that prefix into HARP and then send a SET message of our own
1848  * with our full interface NSAP address.
1849  *
1850  * Arguments:
1851  *      oid     - objid from SET message
1852  *      hdr     - pointer to internal SNMP header
1853  *      buf     - pointer to SET buffer
1854  *      s       - socket to send messages on
1855  *
1856  * Returns:
1857  *      none
1858  *
1859  */
1860 void
1861 set_prefix ( oid, hdr, intf )
1862         Objid           *oid;
1863         Snmp_Header     *hdr;
1864         int             intf;
1865 {
1866         struct atmsetreq        asr;
1867         Atm_addr                *aa;
1868         int                     fd;
1869         int                     i;
1870
1871         /*
1872          * Build IOCTL request to set prefix
1873          */
1874         asr.asr_opcode = AIOCS_SET_PRF;
1875         strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1876                 sizeof(asr.asr_prf_intf ) );
1877         /*
1878          * Pull prefix out of received Objid
1879          *      save in set_prefix IOCTL and addressEntry table
1880          */
1881         for ( i = 0; i < oid->oid[13]; i++ ) {
1882                 asr.asr_prf_pref[i] = oid->oid[i + 14];
1883         }
1884
1885         /*
1886          * Pass new prefix to the HARP kernel
1887          */
1888         fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1889         if ( fd < 0 ) 
1890                 return;
1891         if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1892                 if ( errno != EALREADY ) {
1893                     syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1894                     if ( Log ) {
1895                         write_timestamp();
1896                         fprintf ( Log, "errno %d setting prefix\n",
1897                             errno );
1898                     }
1899                     close ( fd );
1900                     return;
1901                 }
1902         }
1903         close ( fd );
1904
1905         /*
1906          * Reload the cfg/intf info with newly set prefix
1907          */
1908         init_ilmi();
1909
1910         aa = &Intf[intf].anp_addr;
1911
1912         /*
1913          * Copy our NSAP into addressEntry table
1914          */
1915
1916         addressEntry[intf].oid[0] = 0;
1917         for ( i = 0; i < aa->address_length; i++ ) {
1918                 addressEntry[intf].oid[0]++;    /* Increment length */
1919                 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1920
1921         }
1922
1923         return;
1924
1925 }
1926
1927 void
1928 set_address ( hdr, intf )
1929         Snmp_Header     *hdr;
1930         int             intf;
1931 {
1932         Variable        *var;
1933         int             i, j;
1934
1935         PDU_Header = build_generic_header();
1936         PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
1937         var = PDU_Header->head;
1938         /* Copy generic addressEntry OBJID */
1939         UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
1940                 sizeof(Objid) );
1941         /* Set specific instance */
1942         i = var->oid.oid[0] + 1;                /* Get length */
1943         var->oid.oid[i++] = 1;
1944         var->oid.oid[i++] = 1;
1945         var->oid.oid[i++] = 3;
1946         var->oid.oid[i++] = 0;
1947
1948         /* Copy in address length */
1949         var->oid.oid[i++] = addressEntry[intf].oid[0];
1950
1951         /* Copy in address */
1952         for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
1953                 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
1954         var->oid.oid[0] = i - 1;                /* Set new length */
1955
1956         /* Set == VALID */
1957         var->type = ASN_INTEGER;
1958         var->var.ival = 1;
1959
1960         build_pdu ( PDU_Header, PDU_TYPE_SET );
1961         send_resp ( intf, PDU_Header, Resp_Buf );
1962 }
1963
1964 /* 
1965  * Utility to strip off any leading path information from a filename
1966  *      
1967  * Arguments:
1968  *      path            pathname to strip
1969  *      
1970  * Returns:
1971  *      fname           striped filename
1972  * 
1973  */     
1974 char *
1975 basename ( path )
1976         char *path;
1977 {  
1978         char *fname;
1979
1980         if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1981                 fname++;
1982         else
1983                 fname = path;
1984
1985         return ( fname );
1986 }
1987
1988 /*
1989  * Increment Debug Level
1990  *
1991  * Catches SIGUSR1 signal and increments value of Debug_Level
1992  *
1993  * Arguments:
1994  *      sig     - signal number
1995  *
1996  * Returns:
1997  *      none    - Debug_Level incremented
1998  *
1999  */
2000 void
2001 Increment_DL ( sig )
2002         int     sig;
2003 {
2004         Debug_Level++;
2005         if ( Debug_Level && Log == (FILE *)NULL ) {
2006             if ( foregnd ) {
2007                 Log = stderr;
2008             } else {
2009                 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL ) 
2010                     Log = NULL;
2011             }
2012             if ( Log ) {
2013                 setbuf ( Log, NULL );
2014                 write_timestamp();
2015                 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
2016             }
2017         }
2018         signal ( SIGUSR1, Increment_DL );
2019         return;
2020 }
2021
2022 /*
2023  * Decrement Debug Level
2024  *
2025  * Catches SIGUSR2 signal and decrements value of Debug_Level
2026  *
2027  * Arguments:
2028  *      sig     - signal number
2029  *
2030  * Returns:
2031  *      none    - Debug_Level decremented
2032  *
2033  */
2034 void
2035 Decrement_DL ( sig )
2036         int     sig;
2037 {
2038         Debug_Level--;
2039         if ( Debug_Level <= 0 ) {
2040             Debug_Level = 0;
2041             if ( Log ) {
2042                 write_timestamp();
2043                 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
2044                 if ( !foregnd )
2045                     fclose ( Log );
2046                 Log = NULL;
2047             }
2048         }
2049         signal ( SIGUSR2, Decrement_DL );
2050         return;
2051 }
2052
2053 /*
2054  * Loop through GET variable list looking for matches
2055  *
2056  */
2057 void
2058 process_get ( hdr, intf )
2059         Snmp_Header     *hdr;
2060         int             intf;
2061 {
2062         Variable        *var;
2063         int             idx;
2064
2065         var = hdr->head;
2066         while ( var ) {
2067                 idx = find_var ( var );
2068                 switch ( idx ) {
2069                 case SYS_OBJID:
2070                         var->type = ASN_OBJID;
2071                         UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2072                             (caddr_t)&var->var.oval,
2073                                 sizeof(Objid) );
2074                         break;
2075                 case UPTIME_OBJID:
2076                         var->type = ASN_TIMESTAMP;
2077                         var->var.ival = get_ticks();
2078                         break;
2079                 case UNITYPE_OBJID:
2080                         var->type = ASN_INTEGER;
2081                         var->var.ival = UNITYPE_PRIVATE;
2082                         break;
2083                 case UNIVER_OBJID:
2084                         var->type = ASN_INTEGER;
2085                         switch ( Intf[intf].anp_sig_proto ) {
2086                         case ATM_SIG_UNI30:
2087                                 var->var.ival = UNIVER_UNI30;
2088                                 break;
2089                         case ATM_SIG_UNI31:
2090                                 var->var.ival = UNIVER_UNI31;
2091                                 break;
2092                         case ATM_SIG_UNI40:
2093                                 var->var.ival = UNIVER_UNI40;
2094                                 break;
2095                         default:
2096                                 var->var.ival = UNIVER_UNKNOWN;
2097                                 break;
2098                         }
2099                         break;
2100                 case DEVTYPE_OBJID:
2101                         var->type = ASN_INTEGER;
2102                         var->var.ival = DEVTYPE_USER;
2103                         break;
2104                 case MAXVCC_OBJID:
2105                         var->type = ASN_INTEGER;
2106                         var->var.ival = 1024;
2107                         break;
2108                 case PORT_OBJID:
2109                         var->type = ASN_INTEGER;
2110                         var->var.ival = intf + 1;
2111                         break;
2112                 case IPNM_OBJID:
2113                         var->type = ASN_IPADDR;
2114                         get_local_ip ( ilmi_fd[intf],
2115                             &var->var.ival );
2116                         break;
2117                 case ADDRESS_OBJID:
2118                         break;
2119                 case ATMF_PORTID:
2120                         var->type = ASN_INTEGER;
2121                         var->var.ival = 0x30 + intf;
2122                         break;
2123                 case ATMF_SYSID:
2124                         var->type = ASN_OCTET;
2125                         var->var.sval[0] = 6;
2126                         UM_COPY ( (caddr_t)&Cfg[intf].acp_macaddr,
2127                             (caddr_t)&var->var.sval[1], 6 );
2128                         break;
2129                 default:
2130                         /* NO_SUCH */
2131                         break;
2132                 }
2133                 var = var->next;
2134         }
2135         build_pdu ( hdr, PDU_TYPE_GETRESP );
2136         send_resp ( intf, hdr, Resp_Buf );
2137
2138 }
2139
2140 /*
2141  * ILMI State Processing Loop
2142  *
2143  *
2144  */
2145 void
2146 ilmi_do_state ()
2147 {
2148         struct timeval  tvp;
2149         fd_set          rfd;
2150         u_char          buf[1024];
2151         Variable        *var;
2152         int             intf;
2153         int             maxfd = 0;
2154
2155         /*
2156          * Loop forever
2157          */
2158         for ( ; ; ) {
2159             int         count;
2160             int         n;
2161             caddr_t     bpp;
2162             Snmp_Header *Hdr;
2163
2164             /*
2165              * SunOS CC doesn't allow automatic aggregate initialization.
2166              * Initialize to zero which effects a poll operation.
2167              */
2168             tvp.tv_sec = 15;
2169             tvp.tv_usec = 0;
2170
2171             /*
2172              * Clear fd_set and initialize to check this interface
2173              */
2174             FD_ZERO ( &rfd );
2175             for ( intf = 0; intf < MAX_UNITS; intf++ )
2176                 if ( ilmi_fd[intf] > 0 ) {
2177                     FD_SET ( ilmi_fd[intf], &rfd );
2178                     maxfd = MAX ( maxfd, ilmi_fd[intf] );
2179                 }
2180
2181             /*
2182              * Check for new interfaces
2183              */
2184             ilmi_open();
2185
2186             for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2187                 /*
2188                  * Do any pre-message state processing
2189                  */
2190                 switch ( ilmi_state[intf] ) {
2191                 case ILMI_COLDSTART:
2192                         /*
2193                          * Clear addressTable
2194                          */
2195                         UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2196
2197                         /*
2198                          * Start by sending a COLD_START trap. This should cause the
2199                          * remote end to clear the associated prefix/address table(s).
2200                          */
2201                         /* Build ColdStart TRAP header */
2202                         ColdStart_Header = build_cold_start();
2203                         build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2204                         send_resp ( intf, ColdStart_Header, Resp_Buf );
2205
2206                         /*
2207                          * Start a timeout so that if the next state fails, we re-enter
2208                          * ILMI_COLDSTART.
2209                          */
2210                         /* atm_timeout() */
2211         
2212                         /* Enter new state */
2213                         ilmi_state[intf] = ILMI_INIT;
2214                         /* fall into ILMI_INIT */
2215
2216                 case ILMI_INIT:
2217                         /*
2218                          * After a COLD_START, we need to check that the remote end has
2219                          * cleared any tables. Send a GET_NEXT request to check for this.
2220                          * In the event that the table is not empty, or that no reply is
2221                          * received, return to COLD_START state.
2222                          */
2223                         PDU_Header = build_generic_header();
2224                         PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
2225                         var = PDU_Header->head;
2226                         UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2227                             sizeof(Objid) );
2228                         var->type = ASN_NULL;
2229                         var->next = NULL;
2230         
2231                         /*
2232                          * Send GETNEXT request looking for empty ATM Address Table
2233                          */
2234                         PDU_Header->reqid = Req_ID++;
2235                         build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2236                         send_resp ( intf, PDU_Header, Resp_Buf );
2237         
2238                         /*
2239                          * Start a timeout while looking for SET message. If we don't receive
2240                          * a SET, then go back to COLD_START state.
2241                          */
2242                         /* atm_timeout() */
2243                         break;
2244         
2245                 case ILMI_RUNNING:
2246                         /* Normal SNMP processing */
2247                         break;
2248         
2249                 default:
2250                         break;
2251                 }
2252             }
2253
2254             count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2255
2256             for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2257                 /*
2258                  * Check for received messages
2259                  */
2260                 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2261                 
2262                     n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2263                     if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2264                         ilmi_state[intf] = ILMI_COLDSTART;
2265                         close ( ilmi_fd[intf] );
2266                         ilmi_fd[intf] = -1;
2267                     } else {
2268                         if ( Log && Debug_Level > 1 ) fprintf ( Log, "***** state %d ***** read %d bytes from %d (%d) ***** %s *****\n",
2269                             ilmi_state[intf], n, intf, ilmi_fd[intf], PDU_Types[buf[14] - 0xA0] ); {
2270                                 if ( Debug_Level > 2 )
2271                                     hexdump ( (caddr_t)&buf[1], n );
2272                         }
2273                         bpp = (caddr_t)&buf[1];
2274                         if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2275                             continue;
2276         
2277                         /* What we do with this messages depends upon the state we're in */
2278                         switch ( ilmi_state[intf] ) {
2279                         case ILMI_COLDSTART:
2280                             /* We should never be in this state here */
2281                             free_pdu ( Hdr );
2282                             break;
2283                         case ILMI_INIT:
2284                             /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2285                             switch ( Hdr->pdutype ) {
2286                             case PDU_TYPE_GETNEXT:
2287                                 /*
2288                                  * Should be because the remote side is attempting
2289                                  * to verify that our table is empty
2290                                  */
2291                                 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2292                                     (caddr_t)&Objids[ADDRESS_OBJID],
2293                                         Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2294                                         if ( addressEntry[intf].oid[0] ) {
2295                                             /* XXX - FIXME */
2296                                             /* Our table is not empty - return address */
2297                                         }
2298                                 }
2299                                 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2300                                 send_resp ( intf, Hdr, Resp_Buf );
2301                                 break;
2302                             case PDU_TYPE_GETRESP:
2303                                 /*
2304                                  * This should be in response to our GETNEXT.
2305                                  * Check the OIDs and go onto ILMI_RUNNING if
2306                                  * the address table is empty. We can cheat and
2307                                  * not check sequence numbers because we only send
2308                                  * the one GETNEXT request and ILMI says we shouldn't
2309                                  * have interleaved sessions.
2310                                  */
2311                                 /*
2312                                  * First look for empty table. If found, go to next state.
2313                                  */
2314                                 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2315                                     ((Hdr->error == SNMP_ERR_NOERROR) &&
2316                                      ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2317                                       Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2318                                         ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2319                                 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2320                                         /*
2321                                          * Check to see if this matches our address
2322                                          * and if so, that it's a VALID entry.
2323                                          */
2324                                         Atm_addr        *aa;
2325                                         int             l;
2326                                         int             match = 1;
2327
2328                                         aa = &Intf[intf].anp_addr;
2329                                         if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2330                                             for ( l = 0; l < aa->address_length; l++ ) {
2331                                                 if ( (int)((u_char *)(aa->address))[l] !=
2332                                                     Hdr->head->oid.oid[14 + l] ) {
2333                                                         match = 0;
2334                                                 }
2335                                             }
2336                                         }
2337                                         if ( match ) {
2338                                             if ( Hdr->head->var.ival == 1 ) {
2339                                                 ilmi_state[intf] = ILMI_RUNNING;
2340                                             }
2341                                         }
2342                                 }
2343                                 free_pdu ( Hdr );
2344                                 break;
2345                             case PDU_TYPE_SET:
2346                                 /* Look for SET_PREFIX Objid */
2347                                 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2348                                     (caddr_t)&Objids[SETPFX_OBJID],
2349                                         Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2350                                             set_prefix ( &Hdr->head->oid, Hdr, intf );
2351                                             /* Reply to SET before sending our ADDRESS */
2352                                             build_pdu(Hdr, PDU_TYPE_GETRESP);
2353                                             send_resp( intf, Hdr, Resp_Buf );
2354                                             set_address ( Hdr, intf );
2355                                 } else {
2356                                         build_pdu(Hdr, PDU_TYPE_GETRESP);
2357                                         send_resp( intf, Hdr, Resp_Buf );
2358                                 }
2359                                 break;
2360                             case PDU_TYPE_TRAP:
2361                                 /* Remote side wants us to start fresh */
2362                                 free_pdu ( Hdr );
2363                                 break;
2364                             default:
2365                                 /* Ignore */
2366                                 free_pdu ( Hdr );
2367                                 break;
2368                             }
2369                             break;
2370                         case ILMI_REG:
2371                             break;
2372                         case ILMI_RUNNING:
2373                             /* We'll take anything here */
2374                             switch ( Hdr->pdutype ) {
2375                             case PDU_TYPE_GET:
2376                                 process_get ( Hdr, intf );
2377                                 break;
2378                             case PDU_TYPE_GETRESP:
2379                                 /* Ignore GETRESPs */
2380                                 free_pdu ( Hdr );
2381                                 break;
2382                             case PDU_TYPE_GETNEXT:
2383                                 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2384                                 send_resp ( intf, Hdr, Resp_Buf );
2385                                 break;
2386                             case PDU_TYPE_SET:
2387                                 /* Look for SET_PREFIX Objid */
2388                                 if ( oid_ncmp ( (caddr_t)&Hdr->head->oid,
2389                                     (caddr_t)&Objids[SETPFX_OBJID],
2390                                         Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2391                                             set_prefix ( &Hdr->head->oid, Hdr, intf );
2392                                             /* Reply to SET before sending our ADDRESS */
2393                                             build_pdu(Hdr, PDU_TYPE_GETRESP);
2394                                             send_resp( intf, Hdr, Resp_Buf );
2395                                             set_address ( Hdr, intf );
2396                                 } else {
2397                                         build_pdu(Hdr, PDU_TYPE_GETRESP);
2398                                         send_resp( intf, Hdr, Resp_Buf );
2399                                 }
2400                                 break;
2401                             case PDU_TYPE_TRAP:
2402                                 free_pdu ( Hdr );
2403                                 break;
2404                             }
2405                             break;
2406                         default:
2407                             /* Unknown state */
2408                             free_pdu ( Hdr );
2409                             break;
2410                         }
2411                     }                   /* if n > 0 */
2412                 }               /* if received message */
2413             }           /* for each interface */
2414         }       /* for ever loop */
2415
2416 }
2417
2418 int
2419 main ( argc, argv )
2420         int     argc;
2421         char    *argv[];
2422 {
2423         int     c;
2424         int     i;
2425         int     Reset = 0;      /* Should we send a coldStart and exit? */
2426
2427         /*
2428          * What are we running as? (argv[0])
2429          */
2430         progname = strdup ( (char *)basename ( argv[0] ) );
2431         /*
2432          * What host are we
2433          */
2434         gethostname ( hostname, sizeof ( hostname ) );
2435
2436         /*
2437          * Ilmid needs to run as root to set prefix
2438          */
2439         if ( getuid() != 0 ) {
2440                 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2441                 exit ( -1 );
2442         }
2443
2444         /*
2445          * Parse arguments
2446          */
2447         while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2448             switch ( c ) {
2449                 case 'd':
2450                         Debug_Level = atoi ( optarg );
2451                         break;
2452                 case 'f':
2453                         foregnd++;
2454                         break;
2455                 case 'r':
2456                         Reset++;
2457                         break;
2458                 case '?':
2459                         fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2460                                 progname );
2461                         exit ( -1 );
2462 /* NOTREACHED */
2463                         break;
2464             }
2465
2466         /*
2467          * If we're not doing debugging, run in the background
2468          */
2469         if ( foregnd == 0 ) {
2470                 if ( daemon ( 0, 0 ) )
2471                         err ( 1, "Can't fork" );
2472         } else
2473                 ; /* setbuf ( stdout, NULL ); */
2474
2475         signal ( SIGUSR1, Increment_DL );
2476         signal ( SIGUSR2, Decrement_DL );
2477
2478         /*
2479          * Open log file
2480          */
2481         if ( Debug_Level ) {
2482             if ( foregnd ) {
2483                 Log = stderr;
2484             } else {
2485                 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2486                     Log = NULL;
2487             }
2488         }
2489         if ( Log )
2490             setbuf ( Log, NULL );
2491
2492         /*
2493          * Get our startup time
2494          */
2495         (void) gettimeofday ( &starttime, NULL );
2496         starttime.tv_sec--;
2497         starttime.tv_usec += 1000000;
2498
2499         /* Randomize starting request ID */
2500         Req_ID = starttime.tv_sec;
2501
2502         /*
2503          * Reset all the interface descriptors
2504          */
2505         for ( i = 0; i < MAX_UNITS; i++ ) {
2506                 ilmi_fd[i] = -1;
2507         }
2508         /*
2509          * Try to open all the interfaces
2510          */
2511         ilmi_open ();
2512
2513         /*
2514          * If we're just sending a coldStart end exiting...
2515          */
2516         if ( Reset ) {
2517                 for ( i = 0; i < MAX_UNITS; i++ )
2518                         if ( ilmi_fd[i] >= 0 ) {
2519                             /* Build ColdStart TRAP header */
2520                             ColdStart_Header = build_cold_start();
2521                             build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2522                             send_resp ( i, ColdStart_Header, Resp_Buf );
2523                             if ( Debug_Level > 1 && Log ) {
2524                                 write_timestamp();
2525                                 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2526                                     i, ilmi_fd[i] );
2527                             }
2528                             close ( ilmi_fd[i] );
2529                         }
2530                 exit ( 2 );
2531         }
2532
2533         ilmi_do_state();
2534
2535         exit(0);
2536 }
2537