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