efe0712bd46e79152b0a5610852a4128a0a07b10
[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.8 2006/10/16 00:15:35 pavalos 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 const 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 const 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 const 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 static const char       *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
334                              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
335
336 /*
337  * Write a syslog() style timestamp
338  *
339  * Write a syslog() style timestamp with month, day, time and hostname
340  * to the log file.
341  *
342  * Arguments:
343  *      none
344  *
345  * Returns:
346  *      none
347  *
348  */
349 static void
350 write_timestamp(void)
351 {
352         time_t          clk;
353         struct tm       *tm;
354
355         clk = time ( (time_t)NULL );
356         tm = localtime ( &clk );
357
358         if ( Log && Debug_Level > 1 )
359             if ( Log != stderr )
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 );
363
364         return;
365
366 }
367
368 /*
369  * Utility to pretty print buffer as hex dumps
370  * 
371  * Arguments:
372  *      bp      - buffer pointer
373  *      len     - length to pretty print
374  *
375  * Returns:
376  *      none
377  *
378  */
379 static void
380 hexdump ( u_char *bp, int len )
381 {
382         int     i, j;
383
384         /*
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.
388          */
389         for ( i = 0; i < len; i += 16 ) {
390                 if ( Log )
391                         write_timestamp();
392                 for ( j = 0; j < 4 && j + i < len; j++ )
393                     if ( Log )
394                         fprintf ( Log, "%.2x ", *bp++ );
395                 if ( Log )
396                     fprintf ( Log, " " );
397                 for ( ; j < 8 && j + i < len; j++ )
398                     if ( Log )
399                         fprintf ( Log, "%.2x ", *bp++ );
400                 if ( Log ) {
401                     fprintf ( Log, "  " );
402                     fflush ( Log );
403                 }
404                 for ( ; j < 12 && j + i < len; j++ )
405                     if ( Log )
406                         fprintf ( Log, "%.2x ", *bp++ );
407                 if ( Log )
408                     fprintf ( Log, " " );
409                 for ( ; j < 16 && j + i < len; j++ )
410                     if ( Log )
411                         fprintf ( Log, "%.2x ", *bp++ );
412                 if ( Log ) {
413                     fprintf ( Log, "\n" );
414                     fflush ( Log );
415                 }
416         }
417
418         return;
419
420 }
421
422 /*
423  * Get lengths from PDU encodings
424  *
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.
430  *
431  * Arguments:
432  *      bufp    - pointer to buffer pointer
433  *      plen    - pointer to PDU length or NULL if not a concern
434  *
435  * Returns: 
436  *      bufp    - updated buffer pointer
437  *      plen    - (possibly) adjusted pdu length
438  *      <len>   - decoded length
439  *
440  */
441 static int
442 asn_get_pdu_len ( u_char **bufp, int *plen )
443 {
444         u_char  *bp = *bufp;
445         int     len = 0;
446         int     i, b;
447
448         b = *bp++;
449         if ( plen )
450                 (*plen)--;
451          if ( b & 0x80 ) {
452                 for ( i = 0; i < (b & ~0x80); i++ ) {
453                         len = len * 256 + *bp++;
454                         if ( plen )
455                                 (*plen)--;
456                 }
457         } else
458                 len = b;
459
460         *bufp = bp;
461         return ( len );
462 }
463
464 /*
465  * Get an 7-bit encoded value.
466  *
467  * Get a value which is represented using a 7-bit encoding. The last
468  * byte in the stream has the high-bit clear.
469  *
470  * Arguments:
471  *      bufp    - pointer to the buffer pointer
472  *      len     - pointer to the buffer length
473  *
474  * Returns:
475  *      bufp    - updated buffer pointer
476  *      len     - updated buffer length
477  *      <val>   - value encoding represented
478  *
479  */
480 static int
481 asn_get_encoded ( u_char **bufp, int *len )
482 {
483         u_char  *bp = *bufp;
484         int     val = 0;
485         int     l = *len;
486
487         /*
488          * Keep going while high bit is set
489          */
490         do {
491                 /*
492                  * Each byte can represent 7 bits
493                  */
494                 val = ( val << 7 ) + ( *bp & ~0x80 );
495                 l--;
496         } while ( *bp++ & 0x80 );
497
498         *bufp = bp;             /* update buffer pointer */
499         *len = l;               /* update buffer length */
500
501         return ( val );
502 }
503
504 /*
505  * Get a BER encoded integer
506  *
507  * Intergers are encoded as one byte length followed by <length> data bytes
508  *
509  * Arguments:
510  *      bufp    - pointer to the buffer pointer
511  *      plen    - pointer to PDU length or NULL if not a concern
512  *
513  * Returns:
514  *      bufp    - updated buffer pointer 
515  *      plen    - (possibly) updated PDU length
516  *      <val>   - value of encoded integer
517  *
518  */
519 static int
520 asn_get_int ( u_char **bufp, int *plen )
521 {
522         int     i;
523         int     len;
524         int     v = 0;
525         u_char  *bp = *bufp;
526
527         len = *bp++;
528         if ( plen )
529                 (*plen)--;
530         for ( i = 0; i < len; i++ ) {
531                 v = (v * 256) + *bp++;
532                 if ( plen )
533                         (*plen)--;
534         }
535         *bufp = bp;
536         return ( v );
537 }
538
539 /*
540  * Set a BER encoded integer
541  *
542  * Arguments:
543  *      bufp    - pointer to buffer pointer where we are to set int in
544  *      val     - integer value to set
545  *
546  * Returns:
547  *      none
548  *      <bufp>  - updated buffer pointer
549  *
550  */
551 static void
552 asn_set_int ( u_char **bufp, int val )
553 {
554         union {
555                 int     i;
556                 u_char  c[4];
557         } u;
558         int     len = sizeof(int);
559         unsigned int    i = 0;
560         u_char  *bp = *bufp;
561
562         /* Check for special case where val == 0 */
563         if ( val == 0 ) {
564                 *bp++ = 1;
565                 *bp++ = 0;
566                 *bufp = bp;
567                 return;
568         }
569
570         u.i = htonl ( val );
571
572         while ( u.c[i] == 0  && i++ < sizeof(int) )
573                 len--;
574
575         if ( u.c[i] > 0x7f ) {
576                 i--;
577                 len++;
578         }
579
580         *bp++ = len;
581         UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
582         bp += len;
583         *bufp = bp;
584
585         return;
586 }
587
588 /*
589  * Utility to print a object identifier
590  *
591  * Arguments:
592  *      objid   - pointer to objid representation
593  *
594  * Returns:
595  *      none
596  *
597  */
598 static void
599 print_objid ( Objid *objid )
600 {
601         int     i;
602
603         /*
604          * First oid coded as 40 * X + Y
605          */
606         if ( Log ) {
607             write_timestamp();
608             fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
609                 objid->oid[1] % 40 );
610         }
611         for ( i = 2; i <= objid->oid[0]; i++ )
612             if ( Log )
613                 fprintf ( Log, ".%d", objid->oid[i] );
614         if ( Log )
615             fprintf ( Log, "\n" );
616
617         return;
618 }
619
620 /*
621  * Get Object Identifier
622  *
623  * Arguments:
624  *      bufp    - pointer to buffer pointer
625  *      objid   - pointer to objid buffer
626  *      plen    - pointer to PDU length or NULL of not a concern
627  *
628  * Returns:
629  *      bufp    - updated buffer pointer
630  *      objid   - internal representation of encoded objid
631  *      plen    - (possibly) adjusted PDU length
632  *
633  */
634 static void
635 asn_get_objid ( u_char **bufp, Objid *objid, int *plen )
636 {
637         int     len;
638         u_char  *bp = *bufp;
639         int     *ip = (int *)objid + 1; /* First byte will contain length */
640         int     oidlen = 0;
641
642         len = *bp++;
643         if ( plen )
644                 (*plen)--;
645         while ( len ) {
646                 *ip++ = asn_get_encoded ( &bp, &len );
647                 if ( plen )
648                         (*plen)--;
649                 oidlen++;
650         }
651         objid->oid[0] = oidlen;
652         *bufp = bp;
653
654         return;
655 }
656
657 /*
658  * Put OBJID - assumes elements <= 16383 for two byte coding
659  *
660  */
661 static int
662 asn_put_objid ( u_char **bufp, Objid *objid )
663 {
664         int     len = 0;
665         u_char  *bp = *bufp;
666         u_char  *cpp;
667         int     i;
668
669         cpp = bp;
670         *bp++ = objid->oid[0];
671         len++;
672         for ( i = 1; i <= objid->oid[0]; i++ ) {
673                 u_int   c = objid->oid[i];
674
675                 while ( c > 127 ) {
676                         *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
677                         len++;
678                         c &= 0x7f;              /* XXX - assumption of two bytes */
679                         (*cpp)++;
680                 }
681                 *bp++ = c;
682                 len++;
683         }
684
685         *bufp = bp;
686         return ( len );
687
688 }
689
690 /*
691  * Get OCTET STRING
692  *
693  * Octet strings are encoded as a 7-bit encoded length followed by <len>
694  * data bytes;
695  *
696  * Arguments:
697  *      bufp    - pointer to buffer pointer
698  *      octet   - pointer to octet buffer
699  *      plen    - pointer to PDU length
700  *
701  * Returns:
702  *      bufp    - updated buffer pointer
703  *      octet   - encoded Octet String
704  *      plen    - (possibly) adjusted PDU length
705  *
706  */ 
707 static void
708 asn_get_octet ( u_char **bufp, char *octet, int *plen )
709 {
710         u_char  *bp = *bufp;
711         int     i = 0;
712         int     len = 0;
713
714         /*
715          * &i is really a dummy value here as we don't keep track
716          * of the ongoing buffer length
717          */
718         len = asn_get_encoded ( &bp, &i );
719
720         for ( i = 0; i < len; i++ ) {
721                 *octet++ = *bp++;
722                 if ( plen )
723                         (*plen)--;
724         }
725
726         *bufp = bp;
727
728         return;
729
730 }
731
732 /*
733  * Utility to print SNMP PDU header information
734  *
735  * Arguments:
736  *      Hdr     - pointer to internal SNMP header structure
737  *
738  * Returns:
739  *      none
740  *
741  */
742 static void
743 print_header ( Snmp_Header *Hdr )
744 {
745         Variable        *var;
746
747         if ( Log ) {
748             write_timestamp();
749             fprintf ( Log,
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] );
753             write_timestamp();
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 );
757         }
758
759         var = Hdr->head;
760         while ( var ) {
761                 if ( Log ) {
762                         write_timestamp();
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 ) {
770                         case ASN_INTEGER:
771                                 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
772                                 break;
773                         case ASN_NULL:
774                                 fprintf ( Log, "NULL" );
775                                 break;
776                         default:
777                                 fprintf ( Log, "[0x%x]", var->type );
778                                 break;
779                         }
780                         fprintf ( Log, "\n" );
781                 }
782                 var = var->next;
783         }
784
785         return;
786
787 }
788
789 /*
790  * Pull OID's from GET/SET message
791  *
792  * Arguments:
793  *      h       - pointer to Snmp_Header
794  *      bp      - pointer to input PDU
795  *
796  * Returns:
797  *      none
798  *
799  */
800 static void
801 parse_oids ( Snmp_Header *h, u_char **bp )
802 {
803         int             len = h->varlen;
804         int             sublen;
805         Variable        *var;
806         u_char          *bufp = *bp;
807
808         while ( len > 0 ) {
809             if ( *bufp++ == ASN_SEQUENCE ) {
810                 len--;
811
812                 /* Create new Variable instance */
813                 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
814                 {
815                         *bp = bufp;
816                         return;
817                 }
818                 /* Link to tail */
819                 if ( h->tail )
820                         h->tail->next = var;
821                 /* Set head iff NULL */
822                 if ( h->head == NULL ) {
823                         h->head = var;
824                 }
825                 /* Adjust tail */
826                 h->tail = var;
827
828                 /* Get length of variable sequence */
829                 sublen = asn_get_pdu_len ( &bufp, &len );
830                 /* Should be OBJID type */
831                 if ( *bufp++ != ASN_OBJID ) {
832                         *bp = bufp;
833                         return;
834                 }
835                 asn_get_objid ( &bufp, &var->oid, &len );
836                 var->type = *bufp++;
837                 len--;
838                 switch ( var->type ) {
839                 case ASN_INTEGER:
840                         var->var.ival = asn_get_int ( &bufp, &len );
841                         break;
842                 case ASN_NULL:
843                         bufp++;
844                         len--;
845                         break;
846                 case ASN_OBJID:
847                         asn_get_objid ( &bufp, &var->var.oval, &len );
848                         break;
849                 case ASN_OCTET:
850                         asn_get_octet ( &bufp, var->var.sval, &len );
851                         break;
852                 default:
853                         if ( Log ) {
854                                 write_timestamp();
855                                 fprintf ( Log, "Unknown variable type: %d\n",
856                                         var->type );
857                         }
858                         break;
859                 }
860                 var->next = NULL;
861             } else
862                 break;
863         }
864
865         *bp = bufp;
866         return;
867 }
868
869 /*
870  * Crack the SNMP header
871  *
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
874  * index values.
875  *
876  * Arguments:
877  *      bufp    - pointer to buffer pointer
878  *
879  * Returns:
880  *      bufp    - updated buffer pointer
881  *              - generated SNMP header
882  *
883  */
884 static Snmp_Header *
885 asn_get_header ( u_char **bufp )
886 {
887         Snmp_Header     *h;
888         u_char          *bp = *bufp;
889         int             len = 0;
890         int             dummy = 0;
891
892         /*
893          * Allocate memory to hold the SNMP header
894          */
895         if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
896                 return ( (Snmp_Header *)NULL );
897
898         /*
899          * Ensure that we wipe the slate clean
900          */
901         UM_ZERO ( h, sizeof ( Snmp_Header ) );
902
903         /*
904          * PDU has to start as SEQUENCE OF
905          */
906         if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
907                 return ( (Snmp_Header *)NULL );
908
909         /*
910          * Get the length of remaining PDU data
911          */
912         h->pdulen = asn_get_pdu_len ( &bp, NULL );
913
914         /*
915          * We expect to find an integer encoding Version-1
916          */
917         if ( *bp++ != ASN_INTEGER ) {
918                 return ( (Snmp_Header *)NULL );
919         }
920         h->version = asn_get_int ( &bp, NULL );
921
922         /*
923          * After the version, we need the community name
924          */
925         if ( *bp++ != ASN_OCTET ) {
926                 return ( (Snmp_Header *)NULL );
927         }
928         asn_get_octet ( &bp, h->community, NULL );
929
930         /*
931          * Single byte PDU type
932          */
933         h->pdutype = *bp++;
934
935         /*
936          * If this isn't a TRAP PDU, then look for the rest of the header
937          */
938         if ( h->pdutype != PDU_TYPE_TRAP ) {    /* TRAP uses different format */
939
940                 asn_get_pdu_len ( &bp, &dummy );
941
942                 /* Request ID */
943                 if ( *bp++ != ASN_INTEGER ) {
944                         UM_FREE ( h );
945                         return ( (Snmp_Header *)NULL );
946                 }
947                 h->reqid = asn_get_int ( &bp, NULL );
948
949                 /* Error Status */
950                 if ( *bp++ != ASN_INTEGER ) {
951                         UM_FREE ( h );
952                         return ( (Snmp_Header *)NULL );
953                 }
954                 h->error = asn_get_int ( &bp, NULL );
955
956                 /* Error Index */
957                 if ( *bp++ != ASN_INTEGER ) {
958                         UM_FREE ( h );
959                         return ( (Snmp_Header *)NULL );
960                 }
961                 h->erridx = asn_get_int ( &bp, NULL );
962
963                 /* Sequence of... */
964                 if ( *bp++ != ASN_SEQUENCE ) {
965                         UM_FREE ( h );
966                         return ( (Snmp_Header *)NULL );
967                 }
968                 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
969                 h->varlen += ( len - 1 );
970
971                 parse_oids ( h, &bp );
972         }
973
974         *bufp = bp;
975
976         if ( Log && Debug_Level )
977                 print_header ( h );
978
979         return ( h );
980
981 }
982
983 /*
984  * Compare two internal OID representations
985  *
986  * Arguments:
987  *      oid1    - Internal Object Identifier
988  *      oid2    - Internal Object Identifier
989  *
990  * Returns:
991  *      0       - Objid's match
992  *      1       - Objid's don't match
993  *
994  */
995 static int
996 oid_cmp ( Objid *oid1, Objid *oid2 )
997 {
998         int     i;
999         int     len;
1000
1001         /*
1002          * Compare lengths
1003          */
1004         if ( !(oid1->oid[0] == oid2->oid[0] ) )
1005                 /* Different lengths */
1006                 return ( 1 );
1007
1008         len = oid1->oid[0];
1009
1010         /*
1011          * value by value compare
1012          */
1013         for ( i = 1; i <= len; i++ ) {
1014                 if ( !(oid1->oid[i] == oid2->oid[i]) )
1015                         /* values don't match */
1016                         return ( 1 );
1017         }
1018
1019         /* Objid's are identical */
1020         return ( 0 );
1021 }
1022
1023 /*
1024  * Compare two internal OID representations
1025  *
1026  * Arguments:
1027  *      oid1    - Internal Object Identifier
1028  *      oid2    - Internal Object Identifier
1029  *      len     - Length of OID to compare
1030  *
1031  * Returns:
1032  *      0       - Objid's match
1033  *      1       - Objid's don't match
1034  *
1035  */
1036 static int
1037 oid_ncmp ( Objid *oid1, Objid *oid2, int len )
1038 {
1039         int     i;
1040
1041         /*
1042          * value by value compare
1043          */
1044         for ( i = 1; i <= len; i++ ) {
1045                 if ( !(oid1->oid[i] == oid2->oid[i]) )
1046                         /* values don't match */
1047                         return ( 1 );
1048         }
1049
1050         /* Objid's are identical */
1051         return ( 0 );
1052 }
1053
1054 /*
1055  * Find the index of a OBJID which matches this Variable instance 
1056  *
1057  * Arguments:
1058  *      var     - pointer to Variable instance
1059  *
1060  * Returns:
1061  *      idx     - index of matched Variable instance
1062  *      -1      - no matching Variable found
1063  *
1064  */
1065 static int
1066 find_var ( Variable *var )
1067 {
1068         unsigned int    i;
1069
1070         for ( i = 0; i < NUM_OIDS; i++ )
1071                 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1072                         return ( i );
1073                 }
1074
1075         return ( -1 );
1076
1077 }
1078
1079 /*
1080  * Return the time process has been running as a number of ticks 
1081  *
1082  * Arguments:
1083  *      none
1084  *
1085  * Returns:
1086  *      number of ticks
1087  *
1088  */
1089 static int
1090 get_ticks(void)
1091 {
1092         struct timeval  timenow;
1093         struct timeval  timediff;
1094
1095         gettimeofday ( &timenow, NULL );
1096         /*
1097          * Adjust for subtraction
1098          */
1099         timenow.tv_sec--;
1100         timenow.tv_usec += 1000000;
1101
1102         /*
1103          * Compute time since 'starttime'
1104          */
1105         timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1106         timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1107
1108         /*
1109          * Adjust difference timeval
1110          */
1111         if ( timediff.tv_usec >= 1000000 ) {
1112                 timediff.tv_usec -= 1000000;
1113                 timediff.tv_sec++;
1114         }
1115
1116         /*
1117          * Compute number of ticks
1118          */
1119         return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1120
1121 }
1122
1123 /*
1124  * Build a response PDU
1125  *
1126  * Arguments:
1127  *      hdr     - pointer to PDU Header with completed Variable list
1128  *
1129  * Returns:
1130  *      none
1131  *
1132  */
1133 static void
1134 build_pdu ( Snmp_Header *hdr, int type )
1135 {
1136         u_char          *bp = Resp_Buf;
1137         u_char          *vpp;
1138         u_char          *ppp;
1139         int             erridx = 0;
1140         int             varidx = 1;
1141         int             varlen = 0;
1142         int             pdulen = 0;
1143         int             traplen = 0;
1144         Variable        *var;
1145
1146         /*
1147          * Clear out the reply
1148          */
1149         UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1150
1151         /* [0] is reserved for overall length */
1152         bp++;
1153
1154         /* Start with SEQUENCE OF */
1155         *bp++ = ASN_SEQUENCE;
1156         /* - assume we can code length in two octets */
1157         *bp++ = 0x82;
1158         bp++;
1159         bp++;
1160         /* Version */
1161         *bp++ = ASN_INTEGER;
1162         asn_set_int ( &bp, hdr->version );
1163         /* Community name */
1164         *bp++ = ASN_OCTET;
1165         *bp++ = strlen ( hdr->community );
1166         UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1167         bp += strlen ( hdr->community );
1168         /* PDU Type */
1169         *bp++ = type;
1170         ppp = bp;
1171         /* Length of OID data - assume it'll fit in one octet */
1172         bp++;
1173
1174         if ( type != PDU_TYPE_TRAP ) {
1175             /* Sequence ID */
1176             *bp++ = ASN_INTEGER;
1177             asn_set_int ( &bp, hdr->reqid );
1178             /*
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.
1181              */
1182             var = hdr->head;
1183             if ( type == PDU_TYPE_GETRESP ) {
1184                 while ( var && erridx == 0 ) {
1185                     if ( var->type != ASN_NULL ) {
1186                             varidx++;
1187                             var = var->next;
1188                     } else
1189                         erridx = varidx;
1190                 }
1191             }
1192
1193             /* Error status */
1194             *bp++ = ASN_INTEGER;
1195             *bp++ = 0x01;       /* length = 1 */
1196             if ( erridx )
1197                 *bp++ = SNMP_ERR_NOSUCHNAME;
1198             else
1199                 *bp++ = SNMP_ERR_NOERROR;
1200             /* Error Index */
1201             *bp++ = ASN_INTEGER;
1202             *bp++ = 0x01;       /* length = 1 */
1203             *bp++ = erridx;     /* index - 0 if no error */
1204         } else {
1205                 /* type == PDU_TYPE_TRAP */
1206
1207                 /* Fill in ENTERPRISE OBJID */
1208                 *bp++ = ASN_OBJID;
1209                 asn_put_objid ( &bp, &hdr->enterprise );
1210
1211                 /* Fill in IP address */
1212                 *bp++ = ASN_IPADDR;
1213                 *bp++ = sizeof ( hdr->ipaddr );
1214                 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1215                 bp += sizeof(hdr->ipaddr);
1216
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 );
1222
1223                 /* Fill in time-stamp  - assume 0 for now */
1224                 *bp++ = ASN_TIMESTAMP;
1225                 asn_set_int ( &bp, 0 );
1226                 
1227                 /* encoded length */
1228                 traplen = ( bp - ppp - 1 );
1229
1230                 /* Continue with variable processing */
1231         }
1232
1233         /* SEQUENCE OF */
1234         *bp++ = ASN_SEQUENCE;
1235         *bp++ = 0x82;
1236         /* - assume we can code length in two octets */
1237         vpp = bp;
1238         varlen = 0;
1239         bp++;
1240         bp++;
1241
1242         /* Install Variables */
1243         var = hdr->head;
1244         varidx = 1;
1245         while ( var ) {
1246                 u_char *bpp;
1247                 int     len = 0;
1248
1249                 /* SEQUENCE OF */
1250                 *bp++ = ASN_SEQUENCE;
1251                 *bp++ = 0x82;
1252                 /* - assume we can code length in two octets */
1253                 bpp = bp;
1254                 bp++;
1255                 bp++;
1256                 /* OBJID */
1257                 *bp++ = ASN_OBJID;
1258                 len++;
1259                 len += asn_put_objid ( &bp, &var->oid );
1260
1261                 if ( erridx && varidx >= erridx ) {
1262                         /* Code this variable as NULL */
1263                         *bp++ = ASN_NULL;
1264                         len++;
1265                         bp++;
1266                         len++;
1267                 } else {
1268                         u_char *lpp;
1269                         /* Variable type */
1270                         *bp++ = var->type;
1271                         len++;
1272                         lpp = bp;
1273                         switch ( var->type ) {
1274                         case ASN_INTEGER:
1275                                 asn_set_int ( &bp, var->var.ival );
1276                                 len += ( *lpp + 1 );
1277                                 break;
1278                         case ASN_OCTET:
1279                                 *bp++ = var->var.sval[0];
1280                                 len++;
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];
1285                                 break;
1286                         case ASN_NULL:
1287                                 *bp++ = 0x00;
1288                                 len++;
1289                                 break;
1290                         case ASN_OBJID:
1291                                 len += asn_put_objid ( &bp, &var->var.oval );
1292                                 break;
1293                         case ASN_SEQUENCE:
1294                                 break;
1295                         case ASN_IPADDR:
1296                                 *bp++ = 4;
1297                                 len++;
1298                                 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1299                                 len += 4;
1300                                 bp += 4;
1301                                 break;
1302                         case ASN_TIMESTAMP:
1303                                 asn_set_int ( &bp, var->var.ival );
1304                                 len += ( *lpp + 1 );
1305                                 break;
1306                         default:
1307                                 break;
1308                         }
1309                 }
1310
1311                 /* Accumulate total Variable sequence length */
1312                 varlen += (len + 4);
1313
1314                 /* Fill in length of this sequence */
1315                 bpp[1] = len & 0xff;
1316                 bpp[0] = len >> 8;
1317
1318                 var = var->next;
1319         }
1320
1321
1322         /* Fill in length of Variable sequence */
1323         vpp[1] = varlen & 0xff;
1324         vpp[0] = varlen >> 8;
1325
1326         if ( type != PDU_TYPE_TRAP ) {
1327                 /* Fill in length of data AFTER PDU type */
1328                 *ppp = varlen + 12 + ppp[2];    /* + length of reqid */
1329         } else {
1330                 /* Fill in length of data AFTER PDU  type */
1331                 *ppp = varlen + traplen + 4;    /* + length of initial sequence of */
1332         }
1333
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;
1338
1339         pdulen = bp - Resp_Buf - 1;
1340
1341         Resp_Buf[0] = pdulen;
1342
1343         hdr->pdutype = type;
1344
1345         return;
1346 }
1347
1348 static void
1349 free_pdu ( Snmp_Header *hdr )
1350 {
1351         Variable        *var;
1352
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 */
1357         }
1358
1359         UM_FREE ( hdr );                                /* Free fixed portion */
1360 }
1361
1362 #if 0
1363 /*
1364  * Set Request ID in PDU
1365  *
1366  * Arguments:
1367  *      resp    - Response PDU buffer
1368  *      reqid   - request id value
1369  *
1370  * Returns:
1371  *      none    - request id may/may not be set
1372  *
1373  */
1374 static void
1375 set_reqid ( u_char *resp, int reqid )
1376 {
1377         u_char          *bp = (u_char *)&resp[18];
1378         union {
1379                 int     i;
1380                 u_char  c[4];
1381         } u;    
1382
1383         u.i = htonl(reqid);
1384
1385         /*
1386          * Replace the current Request ID with the supplied value
1387          */
1388         UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1389
1390         return;
1391 }
1392 #endif
1393
1394 /*
1395  * Send a generic response packet
1396  *
1397  * Arguments:
1398  *      sd      - socket to send the reply on
1399  *      reqid   - original request ID from GET PDU
1400  *      resp    - pointer to the response to send
1401  *
1402  * Returns:
1403  *      none    - response sent
1404  *
1405  */
1406 static void
1407 send_resp ( int intf, Snmp_Header *Hdr, u_char *resp )
1408 {
1409         int     n;
1410
1411         if ( ilmi_fd[intf] > 0 ) {
1412             n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1413             if ( Log && Debug_Level > 1 ) {
1414                 write_timestamp();
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] );
1419             }
1420         }
1421
1422         free_pdu ( Hdr );
1423         return;
1424 }
1425
1426 /*
1427  * Build a COLD_START TRAP PDU
1428  *
1429  */
1430 static Snmp_Header *
1431 build_cold_start(void)
1432 {
1433         Snmp_Header     *hdr;
1434         Variable        *var;
1435
1436         hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1437
1438         hdr->pdulen = 0;
1439         hdr->version = SNMP_VERSION_1 - 1;
1440         snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1441
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,
1446                 sizeof(Objid) );
1447
1448         hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1449         var = hdr->head;
1450         UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1451                 sizeof(Objid) );
1452         var->type = ASN_NULL;
1453
1454         return ( hdr );
1455 }
1456
1457 /*
1458  * Build a Generic PDU Header
1459  *
1460  */
1461 static Snmp_Header *
1462 build_generic_header(void)
1463 {
1464         Snmp_Header     *hdr;
1465
1466         hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1467
1468         hdr->pdulen = 0;
1469         hdr->version = SNMP_VERSION_1 - 1;
1470         snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1471
1472         return ( hdr );
1473 }
1474
1475 /* 
1476  * Initialize information on what physical adapters HARP knows about
1477  *
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.
1481  *      
1482  * Arguments:
1483  *      none
1484  *
1485  * Returns:
1486  *      none            Information from HARP available 
1487  *      
1488  */
1489 static void
1490 init_ilmi(void)  
1491 {
1492         struct  air_cfg_rsp     *cfg_info = NULL;
1493         struct  air_int_rsp    *intf_info = NULL;
1494         int                     buf_len;
1495
1496         /*
1497          * Get configuration info - what's available with 'atm sh config'
1498          */
1499         buf_len = get_cfg_info ( NULL, &cfg_info );
1500         /*
1501          * If error occurred, clear out everything
1502          */
1503         if ( buf_len <= 0 ) {
1504                 UM_ZERO ( Cfg, sizeof(Cfg) );
1505                 UM_ZERO ( Intf, sizeof(Intf) );
1506                 NUnits = 0;
1507                 return;
1508         }
1509
1510         /*
1511          * Move to local storage
1512          */
1513         UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1514         /*
1515          * Compute how many units information was returned for
1516          */
1517         NUnits = buf_len / sizeof(struct air_cfg_rsp);
1518         /* Housecleaning */
1519         UM_FREE ( cfg_info );
1520         cfg_info = NULL;
1521         /*
1522          * Get the per interface information
1523          */
1524         buf_len = get_intf_info ( NULL, &intf_info );
1525         /*
1526          * If error occurred, clear out Intf info
1527          */
1528         if ( buf_len <= 0 ) {
1529                 UM_ZERO ( Intf, sizeof(Intf) );
1530                 return;
1531         }
1532
1533         /*
1534          * Move to local storage
1535          */
1536         UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1537         /* Housecleaning */
1538         UM_FREE ( intf_info );
1539         intf_info = NULL;
1540
1541         return;
1542
1543 }
1544
1545 /*
1546  * Open a new SNMP session for ILMI
1547  *
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
1551  * interface.
1552  *
1553  * Arguments:
1554  *      none
1555  *
1556  * Returns:
1557  *      none
1558  *
1559  */
1560 static void
1561 ilmi_open (void)
1562 {
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;
1569         Atm_addr                subaddr;
1570         char                    nifname[IFNAMSIZ];
1571         int                     optlen;
1572         int                     unit = 0;
1573         u_char                  sig_proto;
1574
1575         init_ilmi();
1576
1577         for ( unit = 0; unit < NUnits; unit++ ) {
1578
1579             /*
1580              * ILMI only makes sense for UNI signalling protocols
1581              */
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 )
1585                     continue;
1586
1587             if ( ilmi_fd[unit] == -1 ) {
1588
1589                 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1590
1591                 if ( ilmi_fd[unit] < 0 ) {
1592                     perror ( "open" );
1593                     continue;
1594                 }
1595
1596                 /*
1597                  * Set interface name. For now, we must have a netif to go on...
1598                  */
1599                 if ( Intf[unit].anp_nif_cnt == 0 ) {
1600                     if ( Debug_Level > 1 && Log ) {
1601                         write_timestamp();
1602                         fprintf ( Log, "No nif on unit %d\n", unit );
1603                     }
1604                     close ( ilmi_fd[unit] );
1605                     ilmi_fd[unit] = -1;
1606                     continue;
1607                 }
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" );
1613                         if ( Log ) {
1614                             write_timestamp();
1615                             fprintf ( Log,
1616                                 "Couldn't set interface name \"%s\"\n",
1617                                     nifname );
1618                         }
1619                         if ( Debug_Level > 1 && Log ) {
1620                             write_timestamp();
1621                             fprintf ( Log, "nifname: closing unit %d\n", unit );
1622                         }
1623                         close ( ilmi_fd[unit] );
1624                         ilmi_fd[unit] = -1;
1625                         continue;
1626                 }
1627
1628                 /*
1629                  * Set up destination SAP
1630                  */
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);
1635 #endif
1636
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,
1642                     0 );
1643                 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1644                     16 );
1645     
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;
1649
1650                 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1651
1652                 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1653
1654                 /*
1655                  * Set up connection parameters
1656                  */
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 ) {
1665                         write_timestamp();
1666                         fprintf ( Log, "aal5: closing unit %d\n", unit );
1667                     }
1668                     close ( ilmi_fd[unit] );
1669                     ilmi_fd[unit] = -1;
1670                     continue;
1671                 }
1672
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)");
1692                 }
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)");
1702                 }
1703
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,
1709                         optlen) < 0) {
1710                     perror("setsockopt(qos)");
1711                 }
1712
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)");
1719                 }
1720
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)");
1726                 }
1727
1728                 /*
1729                  * Now try to connect to destination
1730                  */
1731                 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1732                     sizeof(satm)) < 0 ) {
1733                         perror ( "connect" );
1734                         if ( Debug_Level > 1 && Log ) {
1735                             write_timestamp();
1736                             fprintf ( Log, "connect: closing unit %d\n", unit );
1737                         }
1738                         close ( ilmi_fd[unit] );
1739                         ilmi_fd[unit] = -1;
1740                         continue;
1741                 }
1742
1743                 if ( Debug_Level && Log ) {
1744                     write_timestamp();
1745                     fprintf ( Log, "***** opened unit %d\n", unit );
1746                 }
1747
1748                 ilmi_state[unit] = ILMI_COLDSTART;
1749
1750             }
1751
1752         }
1753
1754         return;
1755
1756 }
1757
1758 /*
1759  * Get our local IP address for this interface
1760  *
1761  * Arguments:
1762  *      s       - socket to find address for
1763  *      aval    - pointer to variable to store address in
1764  *
1765  * Returns:
1766  *      none
1767  *
1768  */
1769 static void
1770 get_local_ip ( int s, long *aval )
1771 {
1772         char                    intf_name[IFNAMSIZ];
1773         int                     namelen = IFNAMSIZ;
1774         struct air_netif_rsp    *net_info = NULL;
1775         struct sockaddr_in      *sin;
1776
1777         /*
1778          * Get physical interface name
1779          */
1780         if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1781             (caddr_t) intf_name, &namelen ) )
1782                 return;
1783
1784         /*
1785          * Get network interface information for this physical interface
1786          */
1787         get_netif_info ( intf_name, &net_info );
1788         if ( net_info == NULL )
1789                 return;
1790
1791         sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1792
1793         /*
1794          * Fill in answer
1795          */
1796         UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1797
1798         UM_FREE ( net_info );
1799
1800         return;
1801
1802 }
1803
1804 /*
1805  * Set local NSAP prefix and then reply with our full NSAP address.
1806  *
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.
1810  *
1811  * Arguments:
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
1816  *
1817  * Returns:
1818  *      none
1819  *
1820  */
1821 static void
1822 set_prefix ( Objid *oid, __unused Snmp_Header *hdr, int intf )
1823 {
1824         struct atmsetreq        asr;
1825         Atm_addr                *aa;
1826         int                     fd;
1827         int                     i;
1828
1829         /*
1830          * Build IOCTL request to set prefix
1831          */
1832         asr.asr_opcode = AIOCS_SET_PRF;
1833         strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1834                 sizeof(asr.asr_prf_intf ) );
1835         /*
1836          * Pull prefix out of received Objid
1837          *      save in set_prefix IOCTL and addressEntry table
1838          */
1839         for ( i = 0; i < oid->oid[13]; i++ ) {
1840                 asr.asr_prf_pref[i] = oid->oid[i + 14];
1841         }
1842
1843         /*
1844          * Pass new prefix to the HARP kernel
1845          */
1846         fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1847         if ( fd < 0 ) 
1848                 return;
1849         if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1850                 if ( errno != EALREADY ) {
1851                     syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1852                     if ( Log ) {
1853                         write_timestamp();
1854                         fprintf ( Log, "errno %d setting prefix\n",
1855                             errno );
1856                     }
1857                     close ( fd );
1858                     return;
1859                 }
1860         }
1861         close ( fd );
1862
1863         /*
1864          * Reload the cfg/intf info with newly set prefix
1865          */
1866         init_ilmi();
1867
1868         aa = &Intf[intf].anp_addr;
1869
1870         /*
1871          * Copy our NSAP into addressEntry table
1872          */
1873
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];
1878
1879         }
1880
1881         return;
1882
1883 }
1884
1885 static void
1886 set_address ( __unused Snmp_Header *hdr, int intf )
1887 {
1888         Variable        *var;
1889         int             i, j;
1890
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,
1896                 sizeof(Objid) );
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;
1903
1904         /* Copy in address length */
1905         var->oid.oid[i++] = addressEntry[intf].oid[0];
1906
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 */
1911
1912         /* Set == VALID */
1913         var->type = ASN_INTEGER;
1914         var->var.ival = 1;
1915
1916         build_pdu ( PDU_Header, PDU_TYPE_SET );
1917         send_resp ( intf, PDU_Header, Resp_Buf );
1918 }
1919
1920 /* 
1921  * Utility to strip off any leading path information from a filename
1922  *      
1923  * Arguments:
1924  *      path            pathname to strip
1925  *      
1926  * Returns:
1927  *      fname           striped filename
1928  * 
1929  */     
1930 static char *
1931 basename ( char *path )
1932 {  
1933         char *fname;
1934
1935         if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1936                 fname++;
1937         else
1938                 fname = path;
1939
1940         return ( fname );
1941 }
1942
1943 /*
1944  * Increment Debug Level
1945  *
1946  * Catches SIGUSR1 signal and increments value of Debug_Level
1947  *
1948  * Arguments:
1949  *      sig     - signal number
1950  *
1951  * Returns:
1952  *      none    - Debug_Level incremented
1953  *
1954  */
1955 static void
1956 Increment_DL ( __unused int sig )
1957 {
1958         Debug_Level++;
1959         if ( Debug_Level && Log == (FILE *)NULL ) {
1960             if ( foregnd ) {
1961                 Log = stderr;
1962             } else {
1963                 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL ) 
1964                     Log = NULL;
1965             }
1966             if ( Log ) {
1967                 setbuf ( Log, NULL );
1968                 write_timestamp();
1969                 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
1970             }
1971         }
1972         signal ( SIGUSR1, Increment_DL );
1973         return;
1974 }
1975
1976 /*
1977  * Decrement Debug Level
1978  *
1979  * Catches SIGUSR2 signal and decrements value of Debug_Level
1980  *
1981  * Arguments:
1982  *      sig     - signal number
1983  *
1984  * Returns:
1985  *      none    - Debug_Level decremented
1986  *
1987  */
1988 static void
1989 Decrement_DL ( __unused int sig )
1990 {
1991         Debug_Level--;
1992         if ( Debug_Level <= 0 ) {
1993             Debug_Level = 0;
1994             if ( Log ) {
1995                 write_timestamp();
1996                 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
1997                 if ( !foregnd )
1998                     fclose ( Log );
1999                 Log = NULL;
2000             }
2001         }
2002         signal ( SIGUSR2, Decrement_DL );
2003         return;
2004 }
2005
2006 /*
2007  * Loop through GET variable list looking for matches
2008  *
2009  */
2010 static void
2011 process_get ( Snmp_Header *hdr, int intf )
2012 {
2013         Variable        *var;
2014         int             idx;
2015
2016         var = hdr->head;
2017         while ( var ) {
2018                 idx = find_var ( var );
2019                 switch ( idx ) {
2020                 case SYS_OBJID:
2021                         var->type = ASN_OBJID;
2022                         UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2023                             (caddr_t)&var->var.oval,
2024                                 sizeof(Objid) );
2025                         break;
2026                 case UPTIME_OBJID:
2027                         var->type = ASN_TIMESTAMP;
2028                         var->var.ival = get_ticks();
2029                         break;
2030                 case UNITYPE_OBJID:
2031                         var->type = ASN_INTEGER;
2032                         var->var.ival = UNITYPE_PRIVATE;
2033                         break;
2034                 case UNIVER_OBJID:
2035                         var->type = ASN_INTEGER;
2036                         switch ( Intf[intf].anp_sig_proto ) {
2037                         case ATM_SIG_UNI30:
2038                                 var->var.ival = UNIVER_UNI30;
2039                                 break;
2040                         case ATM_SIG_UNI31:
2041                                 var->var.ival = UNIVER_UNI31;
2042                                 break;
2043                         case ATM_SIG_UNI40:
2044                                 var->var.ival = UNIVER_UNI40;
2045                                 break;
2046                         default:
2047                                 var->var.ival = UNIVER_UNKNOWN;
2048                                 break;
2049                         }
2050                         break;
2051                 case DEVTYPE_OBJID:
2052                         var->type = ASN_INTEGER;
2053                         var->var.ival = DEVTYPE_USER;
2054                         break;
2055                 case MAXVCC_OBJID:
2056                         var->type = ASN_INTEGER;
2057                         var->var.ival = 1024;
2058                         break;
2059                 case PORT_OBJID:
2060                         var->type = ASN_INTEGER;
2061                         var->var.ival = intf + 1;
2062                         break;
2063                 case IPNM_OBJID:
2064                         var->type = ASN_IPADDR;
2065                         get_local_ip ( ilmi_fd[intf],
2066                             &var->var.aval );
2067                         break;
2068                 case ADDRESS_OBJID:
2069                         break;
2070                 case ATMF_PORTID:
2071                         var->type = ASN_INTEGER;
2072                         var->var.ival = 0x30 + intf;
2073                         break;
2074                 case ATMF_SYSID:
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 );
2079                         break;
2080                 default:
2081                         /* NO_SUCH */
2082                         break;
2083                 }
2084                 var = var->next;
2085         }
2086         build_pdu ( hdr, PDU_TYPE_GETRESP );
2087         send_resp ( intf, hdr, Resp_Buf );
2088
2089 }
2090
2091 /*
2092  * ILMI State Processing Loop
2093  *
2094  *
2095  */
2096 static void
2097 ilmi_do_state (void)
2098 {
2099         struct timeval  tvp;
2100         fd_set          rfd;
2101         u_char          buf[1024];
2102         Variable        *var;
2103         int             intf;
2104         int             maxfd = 0;
2105
2106         /*
2107          * Loop forever
2108          */
2109         for ( ; ; ) {
2110             int         count;
2111             int         n;
2112             u_char      *bpp;
2113             Snmp_Header *Hdr;
2114
2115             /*
2116              * SunOS CC doesn't allow automatic aggregate initialization.
2117              * Initialize to zero which effects a poll operation.
2118              */
2119             tvp.tv_sec = 15;
2120             tvp.tv_usec = 0;
2121
2122             /*
2123              * Clear fd_set and initialize to check this interface
2124              */
2125             FD_ZERO ( &rfd );
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] );
2130                 }
2131
2132             /*
2133              * Check for new interfaces
2134              */
2135             ilmi_open();
2136
2137             for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2138                 /*
2139                  * Do any pre-message state processing
2140                  */
2141                 switch ( ilmi_state[intf] ) {
2142                 case ILMI_COLDSTART:
2143                         /*
2144                          * Clear addressTable
2145                          */
2146                         UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2147
2148                         /*
2149                          * Start by sending a COLD_START trap. This should cause the
2150                          * remote end to clear the associated prefix/address table(s).
2151                          */
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 );
2156
2157                         /*
2158                          * Start a timeout so that if the next state fails, we re-enter
2159                          * ILMI_COLDSTART.
2160                          */
2161                         /* atm_timeout() */
2162         
2163                         /* Enter new state */
2164                         ilmi_state[intf] = ILMI_INIT;
2165                         /* fall into ILMI_INIT */
2166
2167                 case ILMI_INIT:
2168                         /*
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.
2173                          */
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,
2178                             sizeof(Objid) );
2179                         var->type = ASN_NULL;
2180                         var->next = NULL;
2181         
2182                         /*
2183                          * Send GETNEXT request looking for empty ATM Address Table
2184                          */
2185                         PDU_Header->reqid = Req_ID++;
2186                         build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2187                         send_resp ( intf, PDU_Header, Resp_Buf );
2188         
2189                         /*
2190                          * Start a timeout while looking for SET message. If we don't receive
2191                          * a SET, then go back to COLD_START state.
2192                          */
2193                         /* atm_timeout() */
2194                         break;
2195         
2196                 case ILMI_RUNNING:
2197                         /* Normal SNMP processing */
2198                         break;
2199         
2200                 default:
2201                         break;
2202                 }
2203             }
2204
2205             count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2206
2207             for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2208                 /*
2209                  * Check for received messages
2210                  */
2211                 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2212                 
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] );
2217                         ilmi_fd[intf] = -1;
2218                     } else {
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 );
2223                         }
2224                         bpp = (caddr_t)&buf[1];
2225                         if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2226                             continue;
2227         
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 */
2232                             free_pdu ( Hdr );
2233                             break;
2234                         case ILMI_INIT:
2235                             /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2236                             switch ( Hdr->pdutype ) {
2237                             case PDU_TYPE_GETNEXT:
2238                                 /*
2239                                  * Should be because the remote side is attempting
2240                                  * to verify that our table is empty
2241                                  */
2242                                 if ( oid_ncmp ( &Hdr->head->oid,
2243                                     &Objids[ADDRESS_OBJID],
2244                                         Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2245                                         if ( addressEntry[intf].oid[0] ) {
2246                                             /* XXX - FIXME */
2247                                             /* Our table is not empty - return address */
2248                                         }
2249                                 }
2250                                 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2251                                 send_resp ( intf, Hdr, Resp_Buf );
2252                                 break;
2253                             case PDU_TYPE_GETRESP:
2254                                 /*
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.
2261                                  */
2262                                 /*
2263                                  * First look for empty table. If found, go to next state.
2264                                  */
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) {
2271                                         /*
2272                                          * Check to see if this matches our address
2273                                          * and if so, that it's a VALID entry.
2274                                          */
2275                                         Atm_addr        *aa;
2276                                         int             l;
2277                                         int             match = 1;
2278
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] ) {
2284                                                         match = 0;
2285                                                 }
2286                                             }
2287                                         }
2288                                         if ( match ) {
2289                                             if ( Hdr->head->var.ival == 1 ) {
2290                                                 ilmi_state[intf] = ILMI_RUNNING;
2291                                             }
2292                                         }
2293                                 }
2294                                 free_pdu ( Hdr );
2295                                 break;
2296                             case PDU_TYPE_SET:
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 );
2306                                 } else {
2307                                         build_pdu(Hdr, PDU_TYPE_GETRESP);
2308                                         send_resp( intf, Hdr, Resp_Buf );
2309                                 }
2310                                 break;
2311                             case PDU_TYPE_TRAP:
2312                                 /* Remote side wants us to start fresh */
2313                                 free_pdu ( Hdr );
2314                                 break;
2315                             default:
2316                                 /* Ignore */
2317                                 free_pdu ( Hdr );
2318                                 break;
2319                             }
2320                             break;
2321                         case ILMI_REG:
2322                             break;
2323                         case ILMI_RUNNING:
2324                             /* We'll take anything here */
2325                             switch ( Hdr->pdutype ) {
2326                             case PDU_TYPE_GET:
2327                                 process_get ( Hdr, intf );
2328                                 break;
2329                             case PDU_TYPE_GETRESP:
2330                                 /* Ignore GETRESPs */
2331                                 free_pdu ( Hdr );
2332                                 break;
2333                             case PDU_TYPE_GETNEXT:
2334                                 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2335                                 send_resp ( intf, Hdr, Resp_Buf );
2336                                 break;
2337                             case PDU_TYPE_SET:
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 );
2347                                 } else {
2348                                         build_pdu(Hdr, PDU_TYPE_GETRESP);
2349                                         send_resp( intf, Hdr, Resp_Buf );
2350                                 }
2351                                 break;
2352                             case PDU_TYPE_TRAP:
2353                                 free_pdu ( Hdr );
2354                                 break;
2355                             }
2356                             break;
2357                         default:
2358                             /* Unknown state */
2359                             free_pdu ( Hdr );
2360                             break;
2361                         }
2362                     }                   /* if n > 0 */
2363                 }               /* if received message */
2364             }           /* for each interface */
2365         }       /* for ever loop */
2366
2367 }
2368
2369 int
2370 main ( int argc, char *argv[] )
2371 {
2372         int     c;
2373         int     i;
2374         int     Reset = 0;      /* Should we send a coldStart and exit? */
2375
2376         /*
2377          * What are we running as? (argv[0])
2378          */
2379         progname = strdup ( (char *)basename ( argv[0] ) );
2380         /*
2381          * What host are we
2382          */
2383         gethostname ( hostname, sizeof ( hostname ) );
2384
2385         /*
2386          * Ilmid needs to run as root to set prefix
2387          */
2388         if ( getuid() != 0 ) {
2389                 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2390                 exit ( -1 );
2391         }
2392
2393         /*
2394          * Parse arguments
2395          */
2396         while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2397             switch ( c ) {
2398                 case 'd':
2399                         Debug_Level = atoi ( optarg );
2400                         break;
2401                 case 'f':
2402                         foregnd++;
2403                         break;
2404                 case 'r':
2405                         Reset++;
2406                         break;
2407                 case '?':
2408                         fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2409                                 progname );
2410                         exit ( -1 );
2411 /* NOTREACHED */
2412                         break;
2413             }
2414
2415         /*
2416          * If we're not doing debugging, run in the background
2417          */
2418         if ( foregnd == 0 ) {
2419                 if ( daemon ( 0, 0 ) )
2420                         err ( 1, "Can't fork" );
2421         }
2422
2423         signal ( SIGUSR1, Increment_DL );
2424         signal ( SIGUSR2, Decrement_DL );
2425
2426         /*
2427          * Open log file
2428          */
2429         if ( Debug_Level ) {
2430             if ( foregnd ) {
2431                 Log = stderr;
2432             } else {
2433                 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2434                     Log = NULL;
2435             }
2436         }
2437         if ( Log )
2438             setbuf ( Log, NULL );
2439
2440         /*
2441          * Get our startup time
2442          */
2443         gettimeofday ( &starttime, NULL );
2444         starttime.tv_sec--;
2445         starttime.tv_usec += 1000000;
2446
2447         /* Randomize starting request ID */
2448         Req_ID = starttime.tv_sec;
2449
2450         /*
2451          * Reset all the interface descriptors
2452          */
2453         for ( i = 0; i < MAX_UNITS; i++ ) {
2454                 ilmi_fd[i] = -1;
2455         }
2456         /*
2457          * Try to open all the interfaces
2458          */
2459         ilmi_open ();
2460
2461         /*
2462          * If we're just sending a coldStart end exiting...
2463          */
2464         if ( Reset ) {
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 ) {
2472                                 write_timestamp();
2473                                 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2474                                     i, ilmi_fd[i] );
2475                             }
2476                             close ( ilmi_fd[i] );
2477                         }
2478                 exit ( 2 );
2479         }
2480
2481         ilmi_do_state();
2482
2483         exit(0);
2484 }