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