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