Fix stopping of the current process, which was broken by the last commit.
[dragonfly.git] / sbin / atm / ilmid / ilmid.c
blobefe0712bd46e79152b0a5610852a4128a0a07b10
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sbin/atm/ilmid/ilmid.c,v 1.6.2.2 2001/03/04 07:15:30 kris Exp $
27 * @(#) $DragonFly: src/sbin/atm/ilmid/ilmid.c,v 1.8 2006/10/16 00:15:35 pavalos Exp $
31 * User utilities
32 * --------------
34 * Implement very minimal ILMI address registration.
36 * Implement very crude and basic support for "cracking" and
37 * "encoding" SNMP PDU's to support ILMI prefix and NSAP address
38 * registration. Code is not robust nor is it meant to provide any
39 * "real" SNMP support. Much of the code expects predetermined values
40 * and will fail if anything else is found. Much of the "encoding" is
41 * done with pre-computed PDU's.
43 * See "The Simple Book", Marshall T. Rose, particularly chapter 5,
44 * for ASN and BER information.
48 #include <sys/param.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <net/if.h>
52 #include <netinet/in.h>
53 #include <netatm/port.h>
54 #include <netatm/atm.h>
55 #include <netatm/atm_if.h>
56 #include <netatm/atm_sigmgr.h>
57 #include <netatm/atm_sap.h>
58 #include <netatm/atm_sys.h>
59 #include <netatm/atm_ioctl.h>
60 #include <dev/atm/hea/eni_stats.h>
61 #include <dev/atm/hfa/fore_aali.h>
62 #include <dev/atm/hfa/fore_slave.h>
63 #include <dev/atm/hfa/fore_stats.h>
65 #include <err.h>
66 #include <errno.h>
67 #include <libatm.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <syslog.h>
72 #include <time.h>
73 #include <unistd.h>
75 #define MAX_LEN 9180
77 #define MAX_UNITS 8
80 * Define some ASN types
82 #define ASN_INTEGER 0x02
83 #define ASN_OCTET 0x04
84 #define ASN_NULL 0x05
85 #define ASN_OBJID 0x06
86 #define ASN_SEQUENCE 0x30
87 #define ASN_IPADDR 0x40
88 #define ASN_TIMESTAMP 0x43
90 static const char *Var_Types[] = { "", "", "ASN_INTEGER", "", "ASN_OCTET", "ASN_NULL", "ASN_OBJID" };
93 * Define SNMP PDU types
95 #define PDU_TYPE_GET 0xA0
96 #define PDU_TYPE_GETNEXT 0xA1
97 #define PDU_TYPE_GETRESP 0xA2
98 #define PDU_TYPE_SET 0xA3
99 #define PDU_TYPE_TRAP 0xA4
101 static const char *PDU_Types[] = { "GET REQUEST", "GETNEXT REQUEST", "GET RESPONSE", "SET REQUEST",
102 "TRAP" };
105 * Define TRAP codes
107 #define TRAP_COLDSTART 0
108 #define TRAP_WARMSTART 1
109 #define TRAP_LINKDOWN 2
110 #define TRAP_LINKUP 3
111 #define TRAP_AUTHFAIL 4
112 #define TRAP_EGPLOSS 5
113 #define TRAP_ENTERPRISE 6
116 * Define SNMP Version numbers
118 #define SNMP_VERSION_1 1
119 #define SNMP_VERSION_2 2
122 * SNMP Error-status values
124 #define SNMP_ERR_NOERROR 0
125 #define SNMP_ERR_TOOBIG 1
126 #define SNMP_ERR_NOSUCHNAME 2
127 #define SNMP_ERR_BADVALUE 3
128 #define SNMP_ERR_READONLY 4
129 #define SNMP_ERR_GENERR 5
132 * Max string length for Variable
134 #define STRLEN 128
137 * Unknown variable
139 #define VAR_UNKNOWN -1
142 * Define our internal representation of an OBJECT IDENTIFIER
144 struct objid {
145 int oid[128];
147 typedef struct objid Objid;
150 * Define a Veriable classso that we can handle multiple GET/SET's
151 * per PDU.
153 typedef struct variable Variable;
154 struct variable {
155 Objid oid;
156 int type;
157 union {
158 int ival; /* INTEGER/TIMESTAMP */
159 Objid oval; /* OBJID */
160 long aval; /* IPADDR */
161 char sval[STRLEN]; /* OCTET */
162 } var;
163 Variable *next;
167 * Every SNMP PDU has the first four fields of this header. The only type
168 * which doesn't have the last three fields is the TRAP type.
170 struct snmp_header {
171 int pdulen;
172 int version;
173 char community[64];
174 int pdutype;
176 /* GET/GETNEXT/GETRESP/SET */
177 int reqid;
178 int error;
179 int erridx;
181 /* TRAP */
182 Objid enterprise;
183 int ipaddr;
184 int generic_trap;
185 int specific_trap;
187 int varlen;
188 Variable *head,
189 *tail;
191 typedef struct snmp_header Snmp_Header;
193 Snmp_Header *ColdStart_Header;
194 Snmp_Header *PDU_Header;
197 * Define some OBJET IDENTIFIERS that we'll try to reply to:
199 * sysUpTime: number of time ticks since this deamon came up
200 * netpfx_oid: network prefix table
201 * unitype: is this a PRIVATE or PUBLIC network link
202 * univer: which version of UNI are we running
203 * devtype: is this a USER or NODE ATM device
204 * setprefix: used when the switch wants to tell us its NSAP prefix
205 * foresiggrp: FORE specific Objid we see alot of (being connected to FORE
206 * switches...)
208 Objid Objids[] = {
209 #define SYS_OBJID 0
210 {{ 8, 43, 6, 1, 2, 1, 1, 2, 0 }},
211 #define UPTIME_OBJID 1
212 {{ 8, 43, 6, 1, 2, 1, 1, 3, 0 }},
213 #define PORT_OBJID 2
214 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 1, 0 }},
215 #define IPNM_OBJID 3
216 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 2, 0 }},
217 #define LAYER_OBJID 4
218 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 1, 0 }},
219 #define MAXVCC_OBJID 5
220 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 3, 0 }},
221 #define UNITYPE_OBJID 6
222 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 8, 0 }},
223 #define UNIVER_OBJID 7
224 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 9, 0 }},
225 #define DEVTYPE_OBJID 8
226 {{ 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 10, 0 }},
227 #define ADDRESS_OBJID 9
228 {{ 8, 43, 6, 1, 4, 1, 353, 2, 6 }},
229 #define NETPFX_OBJID 10
230 {{ 9, 43, 6, 1, 4, 1, 353, 2, 7, 1 }},
231 #define MY_OBJID 11
232 {{ 7, 43, 6, 1, 4, 1, 9999, 1 }},
233 #define SETPFX_OBJID 12
234 {{ 12, 43, 6, 1, 4, 1, 353, 2, 7, 1, 1, 3, 0 }},
235 #define ENTERPRISE_OBJID 13
236 {{ 8, 43, 6, 1, 4, 1, 3, 1, 1 }},
237 #define ATMF_PORTID 14
238 {{ 10, 43, 6, 1, 4, 1, 353, 2, 1, 4, 0 }},
239 #define ATMF_SYSID 15
240 {{ 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 8, 0 }},
243 #define NUM_OIDS (sizeof(Objids)/sizeof(Objid))
245 #define UNIVER_UNI20 1
246 #define UNIVER_UNI30 2
247 #define UNIVER_UNI31 3
248 #define UNIVER_UNI40 4
249 #define UNIVER_UNKNOWN 5
251 #define UNITYPE_PUBLIC 1
252 #define UNITYPE_PRIVATE 2
254 #define DEVTYPE_USER 1
255 #define DEVTYPE_NODE 2
258 * ILMI protocol states
260 enum ilmi_states {
261 ILMI_UNKNOWN, /* Uninitialized */
262 ILMI_COLDSTART, /* We need to send a COLD_START trap */
263 ILMI_INIT, /* Ensure that switch has reset */
264 ILMI_REG, /* Looking for SET message */
265 ILMI_RUNNING /* Normal processing */
269 * Our (incrementing) Request ID
271 int Req_ID;
274 * Temporary buffer for building response packets. Should help ensure
275 * that we aren't accidently overwriting some other memory.
277 u_char Resp_Buf[1024];
280 * Copy the reponse into a buffer we can modify without
281 * changing the original...
283 #define COPY_RESP(resp) \
284 UM_COPY ( (resp), Resp_Buf, (resp)[0] + 1 )
287 * TRAP generic trap types
289 const char *Traps[] = { "coldStart", "warmStart", "linkDown", "linkUp",
290 "authenticationFailure", "egpNeighborLoss",
291 "enterpriseSpecific" };
294 int NUnits;
297 * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests
299 int ilmi_fd[MAX_UNITS + 1];
301 * enum ilmi_states for this unit
303 int ilmi_state[MAX_UNITS + 1];
305 * Local copy for HARP physical configuration information
307 struct air_cfg_rsp Cfg[MAX_UNITS + 1];
309 * Local copy for HARP interface configuration information
311 struct air_int_rsp Intf[MAX_UNITS + 1];
314 * addressEntry table
316 Objid addressEntry[MAX_UNITS + 1];
319 * When this daemon started
321 struct timeval starttime;
323 int Debug_Level = 0;
324 int foregnd = 0; /* run in the foreground? */
326 char *progname;
327 char hostname[80];
329 /* File to write debug messages to */
330 #define LOG_FILE "/var/log/ilmid"
331 FILE *Log; /* File descriptor for log messages */
333 static const char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
334 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
337 * Write a syslog() style timestamp
339 * Write a syslog() style timestamp with month, day, time and hostname
340 * to the log file.
342 * Arguments:
343 * none
345 * Returns:
346 * none
349 static void
350 write_timestamp(void)
352 time_t clk;
353 struct tm *tm;
355 clk = time ( (time_t)NULL );
356 tm = localtime ( &clk );
358 if ( Log && Debug_Level > 1 )
359 if ( Log != stderr )
360 fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ",
361 Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min,
362 tm->tm_sec, hostname );
364 return;
369 * Utility to pretty print buffer as hex dumps
371 * Arguments:
372 * bp - buffer pointer
373 * len - length to pretty print
375 * Returns:
376 * none
379 static void
380 hexdump ( u_char *bp, int len )
382 int i, j;
385 * Print as 4 groups of four bytes. Each byte is separated
386 * by a space, each block of four is separated, and two blocks
387 * of eight are also separated.
389 for ( i = 0; i < len; i += 16 ) {
390 if ( Log )
391 write_timestamp();
392 for ( j = 0; j < 4 && j + i < len; j++ )
393 if ( Log )
394 fprintf ( Log, "%.2x ", *bp++ );
395 if ( Log )
396 fprintf ( Log, " " );
397 for ( ; j < 8 && j + i < len; j++ )
398 if ( Log )
399 fprintf ( Log, "%.2x ", *bp++ );
400 if ( Log ) {
401 fprintf ( Log, " " );
402 fflush ( Log );
404 for ( ; j < 12 && j + i < len; j++ )
405 if ( Log )
406 fprintf ( Log, "%.2x ", *bp++ );
407 if ( Log )
408 fprintf ( Log, " " );
409 for ( ; j < 16 && j + i < len; j++ )
410 if ( Log )
411 fprintf ( Log, "%.2x ", *bp++ );
412 if ( Log ) {
413 fprintf ( Log, "\n" );
414 fflush ( Log );
418 return;
423 * Get lengths from PDU encodings
425 * Lengths are sometimes encoded as a single byte if the length
426 * is less the 127 but are more commonly encoded as one byte with
427 * the high bit set and the lower seven bits indicating the nuber
428 * of bytes which make up the length value. Trailing data is (to my
429 * knowledge) not 7-bit encoded.
431 * Arguments:
432 * bufp - pointer to buffer pointer
433 * plen - pointer to PDU length or NULL if not a concern
435 * Returns:
436 * bufp - updated buffer pointer
437 * plen - (possibly) adjusted pdu length
438 * <len> - decoded length
441 static int
442 asn_get_pdu_len ( u_char **bufp, int *plen )
444 u_char *bp = *bufp;
445 int len = 0;
446 int i, b;
448 b = *bp++;
449 if ( plen )
450 (*plen)--;
451 if ( b & 0x80 ) {
452 for ( i = 0; i < (b & ~0x80); i++ ) {
453 len = len * 256 + *bp++;
454 if ( plen )
455 (*plen)--;
457 } else
458 len = b;
460 *bufp = bp;
461 return ( len );
465 * Get an 7-bit encoded value.
467 * Get a value which is represented using a 7-bit encoding. The last
468 * byte in the stream has the high-bit clear.
470 * Arguments:
471 * bufp - pointer to the buffer pointer
472 * len - pointer to the buffer length
474 * Returns:
475 * bufp - updated buffer pointer
476 * len - updated buffer length
477 * <val> - value encoding represented
480 static int
481 asn_get_encoded ( u_char **bufp, int *len )
483 u_char *bp = *bufp;
484 int val = 0;
485 int l = *len;
488 * Keep going while high bit is set
490 do {
492 * Each byte can represent 7 bits
494 val = ( val << 7 ) + ( *bp & ~0x80 );
495 l--;
496 } while ( *bp++ & 0x80 );
498 *bufp = bp; /* update buffer pointer */
499 *len = l; /* update buffer length */
501 return ( val );
505 * Get a BER encoded integer
507 * Intergers are encoded as one byte length followed by <length> data bytes
509 * Arguments:
510 * bufp - pointer to the buffer pointer
511 * plen - pointer to PDU length or NULL if not a concern
513 * Returns:
514 * bufp - updated buffer pointer
515 * plen - (possibly) updated PDU length
516 * <val> - value of encoded integer
519 static int
520 asn_get_int ( u_char **bufp, int *plen )
522 int i;
523 int len;
524 int v = 0;
525 u_char *bp = *bufp;
527 len = *bp++;
528 if ( plen )
529 (*plen)--;
530 for ( i = 0; i < len; i++ ) {
531 v = (v * 256) + *bp++;
532 if ( plen )
533 (*plen)--;
535 *bufp = bp;
536 return ( v );
540 * Set a BER encoded integer
542 * Arguments:
543 * bufp - pointer to buffer pointer where we are to set int in
544 * val - integer value to set
546 * Returns:
547 * none
548 * <bufp> - updated buffer pointer
551 static void
552 asn_set_int ( u_char **bufp, int val )
554 union {
555 int i;
556 u_char c[4];
557 } u;
558 int len = sizeof(int);
559 unsigned int i = 0;
560 u_char *bp = *bufp;
562 /* Check for special case where val == 0 */
563 if ( val == 0 ) {
564 *bp++ = 1;
565 *bp++ = 0;
566 *bufp = bp;
567 return;
570 u.i = htonl ( val );
572 while ( u.c[i] == 0 && i++ < sizeof(int) )
573 len--;
575 if ( u.c[i] > 0x7f ) {
576 i--;
577 len++;
580 *bp++ = len;
581 UM_COPY ( (caddr_t)&u.c[sizeof(int)-len], bp, len );
582 bp += len;
583 *bufp = bp;
585 return;
589 * Utility to print a object identifier
591 * Arguments:
592 * objid - pointer to objid representation
594 * Returns:
595 * none
598 static void
599 print_objid ( Objid *objid )
601 int i;
604 * First oid coded as 40 * X + Y
606 if ( Log ) {
607 write_timestamp();
608 fprintf ( Log, ".%d.%d", objid->oid[1] / 40,
609 objid->oid[1] % 40 );
611 for ( i = 2; i <= objid->oid[0]; i++ )
612 if ( Log )
613 fprintf ( Log, ".%d", objid->oid[i] );
614 if ( Log )
615 fprintf ( Log, "\n" );
617 return;
621 * Get Object Identifier
623 * Arguments:
624 * bufp - pointer to buffer pointer
625 * objid - pointer to objid buffer
626 * plen - pointer to PDU length or NULL of not a concern
628 * Returns:
629 * bufp - updated buffer pointer
630 * objid - internal representation of encoded objid
631 * plen - (possibly) adjusted PDU length
634 static void
635 asn_get_objid ( u_char **bufp, Objid *objid, int *plen )
637 int len;
638 u_char *bp = *bufp;
639 int *ip = (int *)objid + 1; /* First byte will contain length */
640 int oidlen = 0;
642 len = *bp++;
643 if ( plen )
644 (*plen)--;
645 while ( len ) {
646 *ip++ = asn_get_encoded ( &bp, &len );
647 if ( plen )
648 (*plen)--;
649 oidlen++;
651 objid->oid[0] = oidlen;
652 *bufp = bp;
654 return;
658 * Put OBJID - assumes elements <= 16383 for two byte coding
661 static int
662 asn_put_objid ( u_char **bufp, Objid *objid )
664 int len = 0;
665 u_char *bp = *bufp;
666 u_char *cpp;
667 int i;
669 cpp = bp;
670 *bp++ = objid->oid[0];
671 len++;
672 for ( i = 1; i <= objid->oid[0]; i++ ) {
673 u_int c = objid->oid[i];
675 while ( c > 127 ) {
676 *bp++ = ( ( c >> 7 ) & 0x7f ) | 0x80;
677 len++;
678 c &= 0x7f; /* XXX - assumption of two bytes */
679 (*cpp)++;
681 *bp++ = c;
682 len++;
685 *bufp = bp;
686 return ( len );
691 * Get OCTET STRING
693 * Octet strings are encoded as a 7-bit encoded length followed by <len>
694 * data bytes;
696 * Arguments:
697 * bufp - pointer to buffer pointer
698 * octet - pointer to octet buffer
699 * plen - pointer to PDU length
701 * Returns:
702 * bufp - updated buffer pointer
703 * octet - encoded Octet String
704 * plen - (possibly) adjusted PDU length
707 static void
708 asn_get_octet ( u_char **bufp, char *octet, int *plen )
710 u_char *bp = *bufp;
711 int i = 0;
712 int len = 0;
715 * &i is really a dummy value here as we don't keep track
716 * of the ongoing buffer length
718 len = asn_get_encoded ( &bp, &i );
720 for ( i = 0; i < len; i++ ) {
721 *octet++ = *bp++;
722 if ( plen )
723 (*plen)--;
726 *bufp = bp;
728 return;
733 * Utility to print SNMP PDU header information
735 * Arguments:
736 * Hdr - pointer to internal SNMP header structure
738 * Returns:
739 * none
742 static void
743 print_header ( Snmp_Header *Hdr )
745 Variable *var;
747 if ( Log ) {
748 write_timestamp();
749 fprintf ( Log,
750 "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x %s\n",
751 Hdr->pdulen, Hdr->version + 1, Hdr->community,
752 Hdr->pdutype, PDU_Types[Hdr->pdutype - PDU_TYPE_GET] );
753 write_timestamp();
754 if ( Hdr->pdutype != PDU_TYPE_TRAP && Log )
755 fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n",
756 Hdr->reqid, Hdr->error, Hdr->erridx );
759 var = Hdr->head;
760 while ( var ) {
761 if ( Log ) {
762 write_timestamp();
763 fprintf ( Log, " Variable Type: %d", var->type );
764 if ( Var_Types[var->type] )
765 fprintf ( Log, " %s", Var_Types[var->type] );
766 fprintf ( Log, "\n\tObject: " );
767 print_objid ( &var->oid );
768 fprintf ( Log, "\tValue: " );
769 switch ( var->type ) {
770 case ASN_INTEGER:
771 fprintf ( Log, "%d (0x%x)\n", var->var.ival, var->var.ival );
772 break;
773 case ASN_NULL:
774 fprintf ( Log, "NULL" );
775 break;
776 default:
777 fprintf ( Log, "[0x%x]", var->type );
778 break;
780 fprintf ( Log, "\n" );
782 var = var->next;
785 return;
790 * Pull OID's from GET/SET message
792 * Arguments:
793 * h - pointer to Snmp_Header
794 * bp - pointer to input PDU
796 * Returns:
797 * none
800 static void
801 parse_oids ( Snmp_Header *h, u_char **bp )
803 int len = h->varlen;
804 int sublen;
805 Variable *var;
806 u_char *bufp = *bp;
808 while ( len > 0 ) {
809 if ( *bufp++ == ASN_SEQUENCE ) {
810 len--;
812 /* Create new Variable instance */
813 if ( ( var = (Variable *)UM_ALLOC(sizeof(Variable)) ) == NULL )
815 *bp = bufp;
816 return;
818 /* Link to tail */
819 if ( h->tail )
820 h->tail->next = var;
821 /* Set head iff NULL */
822 if ( h->head == NULL ) {
823 h->head = var;
825 /* Adjust tail */
826 h->tail = var;
828 /* Get length of variable sequence */
829 sublen = asn_get_pdu_len ( &bufp, &len );
830 /* Should be OBJID type */
831 if ( *bufp++ != ASN_OBJID ) {
832 *bp = bufp;
833 return;
835 asn_get_objid ( &bufp, &var->oid, &len );
836 var->type = *bufp++;
837 len--;
838 switch ( var->type ) {
839 case ASN_INTEGER:
840 var->var.ival = asn_get_int ( &bufp, &len );
841 break;
842 case ASN_NULL:
843 bufp++;
844 len--;
845 break;
846 case ASN_OBJID:
847 asn_get_objid ( &bufp, &var->var.oval, &len );
848 break;
849 case ASN_OCTET:
850 asn_get_octet ( &bufp, var->var.sval, &len );
851 break;
852 default:
853 if ( Log ) {
854 write_timestamp();
855 fprintf ( Log, "Unknown variable type: %d\n",
856 var->type );
858 break;
860 var->next = NULL;
861 } else
862 break;
865 *bp = bufp;
866 return;
870 * Crack the SNMP header
872 * Pull the PDU length, SNMP version, SNMP community and PDU type.
873 * If present, also pull out the Request ID, Error status, and Error
874 * index values.
876 * Arguments:
877 * bufp - pointer to buffer pointer
879 * Returns:
880 * bufp - updated buffer pointer
881 * - generated SNMP header
884 static Snmp_Header *
885 asn_get_header ( u_char **bufp )
887 Snmp_Header *h;
888 u_char *bp = *bufp;
889 int len = 0;
890 int dummy = 0;
893 * Allocate memory to hold the SNMP header
895 if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL )
896 return ( (Snmp_Header *)NULL );
899 * Ensure that we wipe the slate clean
901 UM_ZERO ( h, sizeof ( Snmp_Header ) );
904 * PDU has to start as SEQUENCE OF
906 if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */
907 return ( (Snmp_Header *)NULL );
910 * Get the length of remaining PDU data
912 h->pdulen = asn_get_pdu_len ( &bp, NULL );
915 * We expect to find an integer encoding Version-1
917 if ( *bp++ != ASN_INTEGER ) {
918 return ( (Snmp_Header *)NULL );
920 h->version = asn_get_int ( &bp, NULL );
923 * After the version, we need the community name
925 if ( *bp++ != ASN_OCTET ) {
926 return ( (Snmp_Header *)NULL );
928 asn_get_octet ( &bp, h->community, NULL );
931 * Single byte PDU type
933 h->pdutype = *bp++;
936 * If this isn't a TRAP PDU, then look for the rest of the header
938 if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */
940 asn_get_pdu_len ( &bp, &dummy );
942 /* Request ID */
943 if ( *bp++ != ASN_INTEGER ) {
944 UM_FREE ( h );
945 return ( (Snmp_Header *)NULL );
947 h->reqid = asn_get_int ( &bp, NULL );
949 /* Error Status */
950 if ( *bp++ != ASN_INTEGER ) {
951 UM_FREE ( h );
952 return ( (Snmp_Header *)NULL );
954 h->error = asn_get_int ( &bp, NULL );
956 /* Error Index */
957 if ( *bp++ != ASN_INTEGER ) {
958 UM_FREE ( h );
959 return ( (Snmp_Header *)NULL );
961 h->erridx = asn_get_int ( &bp, NULL );
963 /* Sequence of... */
964 if ( *bp++ != ASN_SEQUENCE ) {
965 UM_FREE ( h );
966 return ( (Snmp_Header *)NULL );
968 h->varlen = ( asn_get_pdu_len ( &bp, &len ) - 1 );
969 h->varlen += ( len - 1 );
971 parse_oids ( h, &bp );
974 *bufp = bp;
976 if ( Log && Debug_Level )
977 print_header ( h );
979 return ( h );
984 * Compare two internal OID representations
986 * Arguments:
987 * oid1 - Internal Object Identifier
988 * oid2 - Internal Object Identifier
990 * Returns:
991 * 0 - Objid's match
992 * 1 - Objid's don't match
995 static int
996 oid_cmp ( Objid *oid1, Objid *oid2 )
998 int i;
999 int len;
1002 * Compare lengths
1004 if ( !(oid1->oid[0] == oid2->oid[0] ) )
1005 /* Different lengths */
1006 return ( 1 );
1008 len = oid1->oid[0];
1011 * value by value compare
1013 for ( i = 1; i <= len; i++ ) {
1014 if ( !(oid1->oid[i] == oid2->oid[i]) )
1015 /* values don't match */
1016 return ( 1 );
1019 /* Objid's are identical */
1020 return ( 0 );
1024 * Compare two internal OID representations
1026 * Arguments:
1027 * oid1 - Internal Object Identifier
1028 * oid2 - Internal Object Identifier
1029 * len - Length of OID to compare
1031 * Returns:
1032 * 0 - Objid's match
1033 * 1 - Objid's don't match
1036 static int
1037 oid_ncmp ( Objid *oid1, Objid *oid2, int len )
1039 int i;
1042 * value by value compare
1044 for ( i = 1; i <= len; i++ ) {
1045 if ( !(oid1->oid[i] == oid2->oid[i]) )
1046 /* values don't match */
1047 return ( 1 );
1050 /* Objid's are identical */
1051 return ( 0 );
1055 * Find the index of a OBJID which matches this Variable instance
1057 * Arguments:
1058 * var - pointer to Variable instance
1060 * Returns:
1061 * idx - index of matched Variable instance
1062 * -1 - no matching Variable found
1065 static int
1066 find_var ( Variable *var )
1068 unsigned int i;
1070 for ( i = 0; i < NUM_OIDS; i++ )
1071 if ( oid_cmp ( &var->oid, &Objids[i] ) == 0 ) {
1072 return ( i );
1075 return ( -1 );
1080 * Return the time process has been running as a number of ticks
1082 * Arguments:
1083 * none
1085 * Returns:
1086 * number of ticks
1089 static int
1090 get_ticks(void)
1092 struct timeval timenow;
1093 struct timeval timediff;
1095 gettimeofday ( &timenow, NULL );
1097 * Adjust for subtraction
1099 timenow.tv_sec--;
1100 timenow.tv_usec += 1000000;
1103 * Compute time since 'starttime'
1105 timediff.tv_sec = timenow.tv_sec - starttime.tv_sec;
1106 timediff.tv_usec = timenow.tv_usec - starttime.tv_usec;
1109 * Adjust difference timeval
1111 if ( timediff.tv_usec >= 1000000 ) {
1112 timediff.tv_usec -= 1000000;
1113 timediff.tv_sec++;
1117 * Compute number of ticks
1119 return ( ( timediff.tv_sec * 100 ) + ( timediff.tv_usec / 10000 ) );
1124 * Build a response PDU
1126 * Arguments:
1127 * hdr - pointer to PDU Header with completed Variable list
1129 * Returns:
1130 * none
1133 static void
1134 build_pdu ( Snmp_Header *hdr, int type )
1136 u_char *bp = Resp_Buf;
1137 u_char *vpp;
1138 u_char *ppp;
1139 int erridx = 0;
1140 int varidx = 1;
1141 int varlen = 0;
1142 int pdulen = 0;
1143 int traplen = 0;
1144 Variable *var;
1147 * Clear out the reply
1149 UM_ZERO ( Resp_Buf, sizeof(Resp_Buf) );
1151 /* [0] is reserved for overall length */
1152 bp++;
1154 /* Start with SEQUENCE OF */
1155 *bp++ = ASN_SEQUENCE;
1156 /* - assume we can code length in two octets */
1157 *bp++ = 0x82;
1158 bp++;
1159 bp++;
1160 /* Version */
1161 *bp++ = ASN_INTEGER;
1162 asn_set_int ( &bp, hdr->version );
1163 /* Community name */
1164 *bp++ = ASN_OCTET;
1165 *bp++ = strlen ( hdr->community );
1166 UM_COPY ( hdr->community, bp, strlen ( hdr->community ) );
1167 bp += strlen ( hdr->community );
1168 /* PDU Type */
1169 *bp++ = type;
1170 ppp = bp;
1171 /* Length of OID data - assume it'll fit in one octet */
1172 bp++;
1174 if ( type != PDU_TYPE_TRAP ) {
1175 /* Sequence ID */
1176 *bp++ = ASN_INTEGER;
1177 asn_set_int ( &bp, hdr->reqid );
1179 * Check to see if all the vaiables were resolved - we do this
1180 * by looking for something which still has a ASN_NULL value.
1182 var = hdr->head;
1183 if ( type == PDU_TYPE_GETRESP ) {
1184 while ( var && erridx == 0 ) {
1185 if ( var->type != ASN_NULL ) {
1186 varidx++;
1187 var = var->next;
1188 } else
1189 erridx = varidx;
1193 /* Error status */
1194 *bp++ = ASN_INTEGER;
1195 *bp++ = 0x01; /* length = 1 */
1196 if ( erridx )
1197 *bp++ = SNMP_ERR_NOSUCHNAME;
1198 else
1199 *bp++ = SNMP_ERR_NOERROR;
1200 /* Error Index */
1201 *bp++ = ASN_INTEGER;
1202 *bp++ = 0x01; /* length = 1 */
1203 *bp++ = erridx; /* index - 0 if no error */
1204 } else {
1205 /* type == PDU_TYPE_TRAP */
1207 /* Fill in ENTERPRISE OBJID */
1208 *bp++ = ASN_OBJID;
1209 asn_put_objid ( &bp, &hdr->enterprise );
1211 /* Fill in IP address */
1212 *bp++ = ASN_IPADDR;
1213 *bp++ = sizeof ( hdr->ipaddr );
1214 UM_COPY ( (caddr_t)&hdr->ipaddr, bp, sizeof(hdr->ipaddr) );
1215 bp += sizeof(hdr->ipaddr);
1217 /* Fill in generic and specific trap types */
1218 *bp++ = ASN_INTEGER;
1219 asn_set_int ( &bp, hdr->generic_trap );
1220 *bp++ = ASN_INTEGER;
1221 asn_set_int ( &bp, hdr->specific_trap );
1223 /* Fill in time-stamp - assume 0 for now */
1224 *bp++ = ASN_TIMESTAMP;
1225 asn_set_int ( &bp, 0 );
1227 /* encoded length */
1228 traplen = ( bp - ppp - 1 );
1230 /* Continue with variable processing */
1233 /* SEQUENCE OF */
1234 *bp++ = ASN_SEQUENCE;
1235 *bp++ = 0x82;
1236 /* - assume we can code length in two octets */
1237 vpp = bp;
1238 varlen = 0;
1239 bp++;
1240 bp++;
1242 /* Install Variables */
1243 var = hdr->head;
1244 varidx = 1;
1245 while ( var ) {
1246 u_char *bpp;
1247 int len = 0;
1249 /* SEQUENCE OF */
1250 *bp++ = ASN_SEQUENCE;
1251 *bp++ = 0x82;
1252 /* - assume we can code length in two octets */
1253 bpp = bp;
1254 bp++;
1255 bp++;
1256 /* OBJID */
1257 *bp++ = ASN_OBJID;
1258 len++;
1259 len += asn_put_objid ( &bp, &var->oid );
1261 if ( erridx && varidx >= erridx ) {
1262 /* Code this variable as NULL */
1263 *bp++ = ASN_NULL;
1264 len++;
1265 bp++;
1266 len++;
1267 } else {
1268 u_char *lpp;
1269 /* Variable type */
1270 *bp++ = var->type;
1271 len++;
1272 lpp = bp;
1273 switch ( var->type ) {
1274 case ASN_INTEGER:
1275 asn_set_int ( &bp, var->var.ival );
1276 len += ( *lpp + 1 );
1277 break;
1278 case ASN_OCTET:
1279 *bp++ = var->var.sval[0];
1280 len++;
1281 UM_COPY ( (caddr_t)&var->var.sval[1],
1282 bp, var->var.sval[0] );
1283 len += var->var.sval[0];
1284 bp += var->var.sval[0];
1285 break;
1286 case ASN_NULL:
1287 *bp++ = 0x00;
1288 len++;
1289 break;
1290 case ASN_OBJID:
1291 len += asn_put_objid ( &bp, &var->var.oval );
1292 break;
1293 case ASN_SEQUENCE:
1294 break;
1295 case ASN_IPADDR:
1296 *bp++ = 4;
1297 len++;
1298 UM_COPY ( (caddr_t)&var->var.aval, bp, 4 );
1299 len += 4;
1300 bp += 4;
1301 break;
1302 case ASN_TIMESTAMP:
1303 asn_set_int ( &bp, var->var.ival );
1304 len += ( *lpp + 1 );
1305 break;
1306 default:
1307 break;
1311 /* Accumulate total Variable sequence length */
1312 varlen += (len + 4);
1314 /* Fill in length of this sequence */
1315 bpp[1] = len & 0xff;
1316 bpp[0] = len >> 8;
1318 var = var->next;
1322 /* Fill in length of Variable sequence */
1323 vpp[1] = varlen & 0xff;
1324 vpp[0] = varlen >> 8;
1326 if ( type != PDU_TYPE_TRAP ) {
1327 /* Fill in length of data AFTER PDU type */
1328 *ppp = varlen + 12 + ppp[2]; /* + length of reqid */
1329 } else {
1330 /* Fill in length of data AFTER PDU type */
1331 *ppp = varlen + traplen + 4; /* + length of initial sequence of */
1334 /* Fill in overall sequence length */
1335 pdulen = *ppp + 7 + strlen ( hdr->community );
1336 Resp_Buf[4] = pdulen & 0x7f;
1337 Resp_Buf[3] = pdulen >> 8;
1339 pdulen = bp - Resp_Buf - 1;
1341 Resp_Buf[0] = pdulen;
1343 hdr->pdutype = type;
1345 return;
1348 static void
1349 free_pdu ( Snmp_Header *hdr )
1351 Variable *var;
1353 while ( hdr->head ) {
1354 var = hdr->head->next; /* Save next link */
1355 UM_FREE ( hdr->head ); /* Free current var */
1356 hdr->head = var; /* Set head to next link */
1359 UM_FREE ( hdr ); /* Free fixed portion */
1362 #if 0
1364 * Set Request ID in PDU
1366 * Arguments:
1367 * resp - Response PDU buffer
1368 * reqid - request id value
1370 * Returns:
1371 * none - request id may/may not be set
1374 static void
1375 set_reqid ( u_char *resp, int reqid )
1377 u_char *bp = (u_char *)&resp[18];
1378 union {
1379 int i;
1380 u_char c[4];
1381 } u;
1383 u.i = htonl(reqid);
1386 * Replace the current Request ID with the supplied value
1388 UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] );
1390 return;
1392 #endif
1395 * Send a generic response packet
1397 * Arguments:
1398 * sd - socket to send the reply on
1399 * reqid - original request ID from GET PDU
1400 * resp - pointer to the response to send
1402 * Returns:
1403 * none - response sent
1406 static void
1407 send_resp ( int intf, Snmp_Header *Hdr, u_char *resp )
1409 int n;
1411 if ( ilmi_fd[intf] > 0 ) {
1412 n = write ( ilmi_fd[intf], (caddr_t)&resp[1], resp[0] );
1413 if ( Log && Debug_Level > 1 ) {
1414 write_timestamp();
1415 fprintf ( Log, "===== Sent %d of %d bytes (%d) =====\n", n, resp[0], ilmi_fd[intf] );
1416 print_header ( Hdr );
1417 if ( Debug_Level > 2 )
1418 hexdump ( (u_char *)&resp[1], resp[0] );
1422 free_pdu ( Hdr );
1423 return;
1427 * Build a COLD_START TRAP PDU
1430 static Snmp_Header *
1431 build_cold_start(void)
1433 Snmp_Header *hdr;
1434 Variable *var;
1436 hdr = (Snmp_Header *)UM_ALLOC (sizeof(Snmp_Header));
1438 hdr->pdulen = 0;
1439 hdr->version = SNMP_VERSION_1 - 1;
1440 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1442 hdr->ipaddr = 0x0; /* 0.0.0.0 */
1443 hdr->generic_trap = TRAP_COLDSTART;
1444 hdr->specific_trap = 0;
1445 UM_COPY ( (caddr_t)&Objids[ENTERPRISE_OBJID], (caddr_t)&hdr->enterprise,
1446 sizeof(Objid) );
1448 hdr->head = (Variable *)UM_ALLOC(sizeof(Variable));
1449 var = hdr->head;
1450 UM_COPY ( (caddr_t)&Objids[UPTIME_OBJID], (caddr_t)&var->oid,
1451 sizeof(Objid) );
1452 var->type = ASN_NULL;
1454 return ( hdr );
1458 * Build a Generic PDU Header
1461 static Snmp_Header *
1462 build_generic_header(void)
1464 Snmp_Header *hdr;
1466 hdr = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header));
1468 hdr->pdulen = 0;
1469 hdr->version = SNMP_VERSION_1 - 1;
1470 snprintf ( hdr->community, sizeof(hdr->community), "ILMI" );
1472 return ( hdr );
1476 * Initialize information on what physical adapters HARP knows about
1478 * Query the HARP subsystem about configuration and physical interface
1479 * information for any currently registered ATM adapters. Store the information
1480 * as arrays for easier indexing by SNMP port/index numbers.
1482 * Arguments:
1483 * none
1485 * Returns:
1486 * none Information from HARP available
1489 static void
1490 init_ilmi(void)
1492 struct air_cfg_rsp *cfg_info = NULL;
1493 struct air_int_rsp *intf_info = NULL;
1494 int buf_len;
1497 * Get configuration info - what's available with 'atm sh config'
1499 buf_len = get_cfg_info ( NULL, &cfg_info );
1501 * If error occurred, clear out everything
1503 if ( buf_len <= 0 ) {
1504 UM_ZERO ( Cfg, sizeof(Cfg) );
1505 UM_ZERO ( Intf, sizeof(Intf) );
1506 NUnits = 0;
1507 return;
1511 * Move to local storage
1513 UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len );
1515 * Compute how many units information was returned for
1517 NUnits = buf_len / sizeof(struct air_cfg_rsp);
1518 /* Housecleaning */
1519 UM_FREE ( cfg_info );
1520 cfg_info = NULL;
1522 * Get the per interface information
1524 buf_len = get_intf_info ( NULL, &intf_info );
1526 * If error occurred, clear out Intf info
1528 if ( buf_len <= 0 ) {
1529 UM_ZERO ( Intf, sizeof(Intf) );
1530 return;
1534 * Move to local storage
1536 UM_COPY ( intf_info, (caddr_t)Intf, buf_len );
1537 /* Housecleaning */
1538 UM_FREE ( intf_info );
1539 intf_info = NULL;
1541 return;
1546 * Open a new SNMP session for ILMI
1548 * Start by updating interface information, in particular, how many
1549 * interfaces are in the system. While we'll try to open sessons on
1550 * all interfaces, this deamon currently can only handle the first
1551 * interface.
1553 * Arguments:
1554 * none
1556 * Returns:
1557 * none
1560 static void
1561 ilmi_open (void)
1563 struct sockaddr_atm satm;
1564 struct t_atm_aal5 aal5;
1565 struct t_atm_traffic traffic;
1566 struct t_atm_bearer bearer;
1567 struct t_atm_qos qos;
1568 struct t_atm_app_name appname;
1569 Atm_addr subaddr;
1570 char nifname[IFNAMSIZ];
1571 int optlen;
1572 int unit = 0;
1573 u_char sig_proto;
1575 init_ilmi();
1577 for ( unit = 0; unit < NUnits; unit++ ) {
1580 * ILMI only makes sense for UNI signalling protocols
1582 sig_proto = Intf[unit].anp_sig_proto;
1583 if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 &&
1584 sig_proto != ATM_SIG_UNI40 )
1585 continue;
1587 if ( ilmi_fd[unit] == -1 ) {
1589 ilmi_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 );
1591 if ( ilmi_fd[unit] < 0 ) {
1592 perror ( "open" );
1593 continue;
1597 * Set interface name. For now, we must have a netif to go on...
1599 if ( Intf[unit].anp_nif_cnt == 0 ) {
1600 if ( Debug_Level > 1 && Log ) {
1601 write_timestamp();
1602 fprintf ( Log, "No nif on unit %d\n", unit );
1604 close ( ilmi_fd[unit] );
1605 ilmi_fd[unit] = -1;
1606 continue;
1608 sprintf ( nifname, "%s0", Intf[unit].anp_nif_pref );
1609 optlen = sizeof ( nifname );
1610 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING,
1611 T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) {
1612 perror ( "setsockopt" );
1613 if ( Log ) {
1614 write_timestamp();
1615 fprintf ( Log,
1616 "Couldn't set interface name \"%s\"\n",
1617 nifname );
1619 if ( Debug_Level > 1 && Log ) {
1620 write_timestamp();
1621 fprintf ( Log, "nifname: closing unit %d\n", unit );
1623 close ( ilmi_fd[unit] );
1624 ilmi_fd[unit] = -1;
1625 continue;
1629 * Set up destination SAP
1631 UM_ZERO ( (caddr_t) &satm, sizeof(satm) );
1632 satm.satm_family = AF_ATM;
1633 #if (defined(BSD) && (BSD >= 199103))
1634 satm.satm_len = sizeof(satm);
1635 #endif
1637 satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT;
1638 satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT;
1639 satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR;
1640 satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc);
1641 ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1642 0 );
1643 ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address,
1644 16 );
1646 satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT;
1647 satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID;
1648 satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802;
1650 satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT;
1652 satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT;
1655 * Set up connection parameters
1657 aal5.forward_max_SDU_size = MAX_LEN;
1658 aal5.backward_max_SDU_size = MAX_LEN;
1659 aal5.SSCS_type = T_ATM_NULL;
1660 optlen = sizeof(aal5);
1661 if ( setsockopt ( ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5,
1662 (caddr_t) &aal5, optlen ) < 0 ) {
1663 perror ( "setsockopt(aal5)" );
1664 if ( Debug_Level > 1 && Log ) {
1665 write_timestamp();
1666 fprintf ( Log, "aal5: closing unit %d\n", unit );
1668 close ( ilmi_fd[unit] );
1669 ilmi_fd[unit] = -1;
1670 continue;
1673 traffic.forward.PCR_high_priority = T_ATM_ABSENT;
1674 traffic.forward.PCR_all_traffic = 100000;
1675 traffic.forward.SCR_high_priority = T_ATM_ABSENT;
1676 traffic.forward.SCR_all_traffic = T_ATM_ABSENT;
1677 traffic.forward.MBS_high_priority = T_ATM_ABSENT;
1678 traffic.forward.MBS_all_traffic = T_ATM_ABSENT;
1679 traffic.forward.tagging = T_NO;
1680 traffic.backward.PCR_high_priority = T_ATM_ABSENT;
1681 traffic.backward.PCR_all_traffic = 100000;
1682 traffic.backward.SCR_high_priority = T_ATM_ABSENT;
1683 traffic.backward.SCR_all_traffic = T_ATM_ABSENT;
1684 traffic.backward.MBS_high_priority = T_ATM_ABSENT;
1685 traffic.backward.MBS_all_traffic = T_ATM_ABSENT;
1686 traffic.backward.tagging = T_NO;
1687 traffic.best_effort = T_YES;
1688 optlen = sizeof(traffic);
1689 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC,
1690 (caddr_t)&traffic, optlen) < 0) {
1691 perror("setsockopt(traffic)");
1693 bearer.bearer_class = T_ATM_CLASS_X;
1694 bearer.traffic_type = T_ATM_NULL;
1695 bearer.timing_requirements = T_ATM_NULL;
1696 bearer.clipping_susceptibility = T_NO;
1697 bearer.connection_configuration = T_ATM_1_TO_1;
1698 optlen = sizeof(bearer);
1699 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP,
1700 (caddr_t)&bearer, optlen) < 0) {
1701 perror("setsockopt(bearer)");
1704 qos.coding_standard = T_ATM_NETWORK_CODING;
1705 qos.forward.qos_class = T_ATM_QOS_CLASS_0;
1706 qos.backward.qos_class = T_ATM_QOS_CLASS_0;
1707 optlen = sizeof(qos);
1708 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos,
1709 optlen) < 0) {
1710 perror("setsockopt(qos)");
1713 subaddr.address_format = T_ATM_ABSENT;
1714 subaddr.address_length = 0;
1715 optlen = sizeof(subaddr);
1716 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB,
1717 (caddr_t)&subaddr, optlen) < 0) {
1718 perror("setsockopt(dest_sub)");
1721 strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN);
1722 optlen = sizeof(appname);
1723 if (setsockopt(ilmi_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME,
1724 (caddr_t)&appname, optlen) < 0) {
1725 perror("setsockopt(appname)");
1729 * Now try to connect to destination
1731 if ( connect ( ilmi_fd[unit], (struct sockaddr *) &satm,
1732 sizeof(satm)) < 0 ) {
1733 perror ( "connect" );
1734 if ( Debug_Level > 1 && Log ) {
1735 write_timestamp();
1736 fprintf ( Log, "connect: closing unit %d\n", unit );
1738 close ( ilmi_fd[unit] );
1739 ilmi_fd[unit] = -1;
1740 continue;
1743 if ( Debug_Level && Log ) {
1744 write_timestamp();
1745 fprintf ( Log, "***** opened unit %d\n", unit );
1748 ilmi_state[unit] = ILMI_COLDSTART;
1754 return;
1759 * Get our local IP address for this interface
1761 * Arguments:
1762 * s - socket to find address for
1763 * aval - pointer to variable to store address in
1765 * Returns:
1766 * none
1769 static void
1770 get_local_ip ( int s, long *aval )
1772 char intf_name[IFNAMSIZ];
1773 int namelen = IFNAMSIZ;
1774 struct air_netif_rsp *net_info = NULL;
1775 struct sockaddr_in *sin;
1778 * Get physical interface name
1780 if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF,
1781 (caddr_t) intf_name, &namelen ) )
1782 return;
1785 * Get network interface information for this physical interface
1787 get_netif_info ( intf_name, &net_info );
1788 if ( net_info == NULL )
1789 return;
1791 sin = (struct sockaddr_in *)&net_info->anp_proto_addr;
1794 * Fill in answer
1796 UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, aval, 4 );
1798 UM_FREE ( net_info );
1800 return;
1805 * Set local NSAP prefix and then reply with our full NSAP address.
1807 * Switch will send a SET message with the NSAP prefix after a coldStart.
1808 * We'll set that prefix into HARP and then send a SET message of our own
1809 * with our full interface NSAP address.
1811 * Arguments:
1812 * oid - objid from SET message
1813 * hdr - pointer to internal SNMP header
1814 * buf - pointer to SET buffer
1815 * s - socket to send messages on
1817 * Returns:
1818 * none
1821 static void
1822 set_prefix ( Objid *oid, __unused Snmp_Header *hdr, int intf )
1824 struct atmsetreq asr;
1825 Atm_addr *aa;
1826 int fd;
1827 int i;
1830 * Build IOCTL request to set prefix
1832 asr.asr_opcode = AIOCS_SET_PRF;
1833 strncpy ( asr.asr_prf_intf, Intf[intf].anp_intf,
1834 sizeof(asr.asr_prf_intf ) );
1836 * Pull prefix out of received Objid
1837 * save in set_prefix IOCTL and addressEntry table
1839 for ( i = 0; i < oid->oid[13]; i++ ) {
1840 asr.asr_prf_pref[i] = oid->oid[i + 14];
1844 * Pass new prefix to the HARP kernel
1846 fd = socket ( AF_ATM, SOCK_DGRAM, 0 );
1847 if ( fd < 0 )
1848 return;
1849 if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) {
1850 if ( errno != EALREADY ) {
1851 syslog ( LOG_ERR, "ilmid: error setting prefix: %m" );
1852 if ( Log ) {
1853 write_timestamp();
1854 fprintf ( Log, "errno %d setting prefix\n",
1855 errno );
1857 close ( fd );
1858 return;
1861 close ( fd );
1864 * Reload the cfg/intf info with newly set prefix
1866 init_ilmi();
1868 aa = &Intf[intf].anp_addr;
1871 * Copy our NSAP into addressEntry table
1874 addressEntry[intf].oid[0] = 0;
1875 for ( i = 0; i < aa->address_length; i++ ) {
1876 addressEntry[intf].oid[0]++; /* Increment length */
1877 addressEntry[intf].oid[i + 1] = (int)((u_char *)(aa->address))[i];
1881 return;
1885 static void
1886 set_address ( __unused Snmp_Header *hdr, int intf )
1888 Variable *var;
1889 int i, j;
1891 PDU_Header = build_generic_header();
1892 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
1893 var = PDU_Header->head;
1894 /* Copy generic addressEntry OBJID */
1895 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
1896 sizeof(Objid) );
1897 /* Set specific instance */
1898 i = var->oid.oid[0] + 1; /* Get length */
1899 var->oid.oid[i++] = 1;
1900 var->oid.oid[i++] = 1;
1901 var->oid.oid[i++] = 3;
1902 var->oid.oid[i++] = 0;
1904 /* Copy in address length */
1905 var->oid.oid[i++] = addressEntry[intf].oid[0];
1907 /* Copy in address */
1908 for ( j = 0; j < addressEntry[intf].oid[0]; j++ )
1909 var->oid.oid[i++] = addressEntry[intf].oid[j + 1];
1910 var->oid.oid[0] = i - 1; /* Set new length */
1912 /* Set == VALID */
1913 var->type = ASN_INTEGER;
1914 var->var.ival = 1;
1916 build_pdu ( PDU_Header, PDU_TYPE_SET );
1917 send_resp ( intf, PDU_Header, Resp_Buf );
1921 * Utility to strip off any leading path information from a filename
1923 * Arguments:
1924 * path pathname to strip
1926 * Returns:
1927 * fname striped filename
1930 static char *
1931 basename ( char *path )
1933 char *fname;
1935 if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL )
1936 fname++;
1937 else
1938 fname = path;
1940 return ( fname );
1944 * Increment Debug Level
1946 * Catches SIGUSR1 signal and increments value of Debug_Level
1948 * Arguments:
1949 * sig - signal number
1951 * Returns:
1952 * none - Debug_Level incremented
1955 static void
1956 Increment_DL ( __unused int sig )
1958 Debug_Level++;
1959 if ( Debug_Level && Log == (FILE *)NULL ) {
1960 if ( foregnd ) {
1961 Log = stderr;
1962 } else {
1963 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
1964 Log = NULL;
1966 if ( Log ) {
1967 setbuf ( Log, NULL );
1968 write_timestamp();
1969 fprintf ( Log, "Raised Debug_Level to %d\n", Debug_Level );
1972 signal ( SIGUSR1, Increment_DL );
1973 return;
1977 * Decrement Debug Level
1979 * Catches SIGUSR2 signal and decrements value of Debug_Level
1981 * Arguments:
1982 * sig - signal number
1984 * Returns:
1985 * none - Debug_Level decremented
1988 static void
1989 Decrement_DL ( __unused int sig )
1991 Debug_Level--;
1992 if ( Debug_Level <= 0 ) {
1993 Debug_Level = 0;
1994 if ( Log ) {
1995 write_timestamp();
1996 fprintf ( Log, "Lowered Debug_Level to %d\n", Debug_Level );
1997 if ( !foregnd )
1998 fclose ( Log );
1999 Log = NULL;
2002 signal ( SIGUSR2, Decrement_DL );
2003 return;
2007 * Loop through GET variable list looking for matches
2010 static void
2011 process_get ( Snmp_Header *hdr, int intf )
2013 Variable *var;
2014 int idx;
2016 var = hdr->head;
2017 while ( var ) {
2018 idx = find_var ( var );
2019 switch ( idx ) {
2020 case SYS_OBJID:
2021 var->type = ASN_OBJID;
2022 UM_COPY ( (caddr_t)&Objids[MY_OBJID],
2023 (caddr_t)&var->var.oval,
2024 sizeof(Objid) );
2025 break;
2026 case UPTIME_OBJID:
2027 var->type = ASN_TIMESTAMP;
2028 var->var.ival = get_ticks();
2029 break;
2030 case UNITYPE_OBJID:
2031 var->type = ASN_INTEGER;
2032 var->var.ival = UNITYPE_PRIVATE;
2033 break;
2034 case UNIVER_OBJID:
2035 var->type = ASN_INTEGER;
2036 switch ( Intf[intf].anp_sig_proto ) {
2037 case ATM_SIG_UNI30:
2038 var->var.ival = UNIVER_UNI30;
2039 break;
2040 case ATM_SIG_UNI31:
2041 var->var.ival = UNIVER_UNI31;
2042 break;
2043 case ATM_SIG_UNI40:
2044 var->var.ival = UNIVER_UNI40;
2045 break;
2046 default:
2047 var->var.ival = UNIVER_UNKNOWN;
2048 break;
2050 break;
2051 case DEVTYPE_OBJID:
2052 var->type = ASN_INTEGER;
2053 var->var.ival = DEVTYPE_USER;
2054 break;
2055 case MAXVCC_OBJID:
2056 var->type = ASN_INTEGER;
2057 var->var.ival = 1024;
2058 break;
2059 case PORT_OBJID:
2060 var->type = ASN_INTEGER;
2061 var->var.ival = intf + 1;
2062 break;
2063 case IPNM_OBJID:
2064 var->type = ASN_IPADDR;
2065 get_local_ip ( ilmi_fd[intf],
2066 &var->var.aval );
2067 break;
2068 case ADDRESS_OBJID:
2069 break;
2070 case ATMF_PORTID:
2071 var->type = ASN_INTEGER;
2072 var->var.ival = 0x30 + intf;
2073 break;
2074 case ATMF_SYSID:
2075 var->type = ASN_OCTET;
2076 var->var.sval[0] = 6;
2077 UM_COPY ( (caddr_t)&Cfg[intf].acp_macaddr,
2078 (caddr_t)&var->var.sval[1], 6 );
2079 break;
2080 default:
2081 /* NO_SUCH */
2082 break;
2084 var = var->next;
2086 build_pdu ( hdr, PDU_TYPE_GETRESP );
2087 send_resp ( intf, hdr, Resp_Buf );
2092 * ILMI State Processing Loop
2096 static void
2097 ilmi_do_state (void)
2099 struct timeval tvp;
2100 fd_set rfd;
2101 u_char buf[1024];
2102 Variable *var;
2103 int intf;
2104 int maxfd = 0;
2107 * Loop forever
2109 for ( ; ; ) {
2110 int count;
2111 int n;
2112 u_char *bpp;
2113 Snmp_Header *Hdr;
2116 * SunOS CC doesn't allow automatic aggregate initialization.
2117 * Initialize to zero which effects a poll operation.
2119 tvp.tv_sec = 15;
2120 tvp.tv_usec = 0;
2123 * Clear fd_set and initialize to check this interface
2125 FD_ZERO ( &rfd );
2126 for ( intf = 0; intf < MAX_UNITS; intf++ )
2127 if ( ilmi_fd[intf] > 0 ) {
2128 FD_SET ( ilmi_fd[intf], &rfd );
2129 maxfd = MAX ( maxfd, ilmi_fd[intf] );
2133 * Check for new interfaces
2135 ilmi_open();
2137 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2139 * Do any pre-message state processing
2141 switch ( ilmi_state[intf] ) {
2142 case ILMI_COLDSTART:
2144 * Clear addressTable
2146 UM_ZERO ( (caddr_t)&addressEntry[intf], sizeof(Objid) );
2149 * Start by sending a COLD_START trap. This should cause the
2150 * remote end to clear the associated prefix/address table(s).
2152 /* Build ColdStart TRAP header */
2153 ColdStart_Header = build_cold_start();
2154 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2155 send_resp ( intf, ColdStart_Header, Resp_Buf );
2158 * Start a timeout so that if the next state fails, we re-enter
2159 * ILMI_COLDSTART.
2161 /* atm_timeout() */
2163 /* Enter new state */
2164 ilmi_state[intf] = ILMI_INIT;
2165 /* fall into ILMI_INIT */
2167 case ILMI_INIT:
2169 * After a COLD_START, we need to check that the remote end has
2170 * cleared any tables. Send a GET_NEXT request to check for this.
2171 * In the event that the table is not empty, or that no reply is
2172 * received, return to COLD_START state.
2174 PDU_Header = build_generic_header();
2175 PDU_Header->head = (Variable *)UM_ALLOC(sizeof(Variable));
2176 var = PDU_Header->head;
2177 UM_COPY ( (caddr_t)&Objids[ADDRESS_OBJID], (caddr_t)&var->oid,
2178 sizeof(Objid) );
2179 var->type = ASN_NULL;
2180 var->next = NULL;
2183 * Send GETNEXT request looking for empty ATM Address Table
2185 PDU_Header->reqid = Req_ID++;
2186 build_pdu ( PDU_Header, PDU_TYPE_GETNEXT );
2187 send_resp ( intf, PDU_Header, Resp_Buf );
2190 * Start a timeout while looking for SET message. If we don't receive
2191 * a SET, then go back to COLD_START state.
2193 /* atm_timeout() */
2194 break;
2196 case ILMI_RUNNING:
2197 /* Normal SNMP processing */
2198 break;
2200 default:
2201 break;
2205 count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp );
2207 for ( intf = 0; intf < MAX_UNITS; intf++ ) {
2209 * Check for received messages
2211 if ( ilmi_fd[intf] > 0 && FD_ISSET ( ilmi_fd[intf], & rfd ) ) {
2213 n = read ( ilmi_fd[intf], (caddr_t)&buf[1], sizeof(buf) - 1 );
2214 if ( n == -1 && ( errno == ECONNRESET || errno == EBADF ) ) {
2215 ilmi_state[intf] = ILMI_COLDSTART;
2216 close ( ilmi_fd[intf] );
2217 ilmi_fd[intf] = -1;
2218 } else {
2219 if ( Log && Debug_Level > 1 ) fprintf ( Log, "***** state %d ***** read %d bytes from %d (%d) ***** %s *****\n",
2220 ilmi_state[intf], n, intf, ilmi_fd[intf], PDU_Types[buf[14] - 0xA0] ); {
2221 if ( Debug_Level > 2 )
2222 hexdump ( (caddr_t)&buf[1], n );
2224 bpp = (caddr_t)&buf[1];
2225 if ( ( Hdr = asn_get_header ( &bpp ) ) == NULL )
2226 continue;
2228 /* What we do with this messages depends upon the state we're in */
2229 switch ( ilmi_state[intf] ) {
2230 case ILMI_COLDSTART:
2231 /* We should never be in this state here */
2232 free_pdu ( Hdr );
2233 break;
2234 case ILMI_INIT:
2235 /* The only messages we care about are GETNEXTs, GETRESPs, and TRAPs */
2236 switch ( Hdr->pdutype ) {
2237 case PDU_TYPE_GETNEXT:
2239 * Should be because the remote side is attempting
2240 * to verify that our table is empty
2242 if ( oid_ncmp ( &Hdr->head->oid,
2243 &Objids[ADDRESS_OBJID],
2244 Objids[ADDRESS_OBJID].oid[0] ) == 0 ) {
2245 if ( addressEntry[intf].oid[0] ) {
2246 /* XXX - FIXME */
2247 /* Our table is not empty - return address */
2250 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2251 send_resp ( intf, Hdr, Resp_Buf );
2252 break;
2253 case PDU_TYPE_GETRESP:
2255 * This should be in response to our GETNEXT.
2256 * Check the OIDs and go onto ILMI_RUNNING if
2257 * the address table is empty. We can cheat and
2258 * not check sequence numbers because we only send
2259 * the one GETNEXT request and ILMI says we shouldn't
2260 * have interleaved sessions.
2263 * First look for empty table. If found, go to next state.
2265 if ((Hdr->error == SNMP_ERR_NOSUCHNAME) ||
2266 ((Hdr->error == SNMP_ERR_NOERROR) &&
2267 ( oid_ncmp ( &Objids[ADDRESS_OBJID], &Hdr->head->oid,
2268 Objids[ADDRESS_OBJID].oid[0] ) == 1 ))) {
2269 ilmi_state[intf] = ILMI_RUNNING; /* ILMI_REG; */
2270 } else if (Hdr->error == SNMP_ERR_NOERROR) {
2272 * Check to see if this matches our address
2273 * and if so, that it's a VALID entry.
2275 Atm_addr *aa;
2276 int l;
2277 int match = 1;
2279 aa = &Intf[intf].anp_addr;
2280 if ( aa->address_length == Hdr->head->oid.oid[13] ) {
2281 for ( l = 0; l < aa->address_length; l++ ) {
2282 if ( (int)((u_char *)(aa->address))[l] !=
2283 Hdr->head->oid.oid[14 + l] ) {
2284 match = 0;
2288 if ( match ) {
2289 if ( Hdr->head->var.ival == 1 ) {
2290 ilmi_state[intf] = ILMI_RUNNING;
2294 free_pdu ( Hdr );
2295 break;
2296 case PDU_TYPE_SET:
2297 /* Look for SET_PREFIX Objid */
2298 if ( oid_ncmp ( &Hdr->head->oid,
2299 &Objids[SETPFX_OBJID],
2300 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2301 set_prefix ( &Hdr->head->oid, Hdr, intf );
2302 /* Reply to SET before sending our ADDRESS */
2303 build_pdu(Hdr, PDU_TYPE_GETRESP);
2304 send_resp( intf, Hdr, Resp_Buf );
2305 set_address ( Hdr, intf );
2306 } else {
2307 build_pdu(Hdr, PDU_TYPE_GETRESP);
2308 send_resp( intf, Hdr, Resp_Buf );
2310 break;
2311 case PDU_TYPE_TRAP:
2312 /* Remote side wants us to start fresh */
2313 free_pdu ( Hdr );
2314 break;
2315 default:
2316 /* Ignore */
2317 free_pdu ( Hdr );
2318 break;
2320 break;
2321 case ILMI_REG:
2322 break;
2323 case ILMI_RUNNING:
2324 /* We'll take anything here */
2325 switch ( Hdr->pdutype ) {
2326 case PDU_TYPE_GET:
2327 process_get ( Hdr, intf );
2328 break;
2329 case PDU_TYPE_GETRESP:
2330 /* Ignore GETRESPs */
2331 free_pdu ( Hdr );
2332 break;
2333 case PDU_TYPE_GETNEXT:
2334 build_pdu ( Hdr, PDU_TYPE_GETRESP );
2335 send_resp ( intf, Hdr, Resp_Buf );
2336 break;
2337 case PDU_TYPE_SET:
2338 /* Look for SET_PREFIX Objid */
2339 if ( oid_ncmp ( &Hdr->head->oid,
2340 &Objids[SETPFX_OBJID],
2341 Objids[SETPFX_OBJID].oid[0] ) == 0 ) {
2342 set_prefix ( &Hdr->head->oid, Hdr, intf );
2343 /* Reply to SET before sending our ADDRESS */
2344 build_pdu(Hdr, PDU_TYPE_GETRESP);
2345 send_resp( intf, Hdr, Resp_Buf );
2346 set_address ( Hdr, intf );
2347 } else {
2348 build_pdu(Hdr, PDU_TYPE_GETRESP);
2349 send_resp( intf, Hdr, Resp_Buf );
2351 break;
2352 case PDU_TYPE_TRAP:
2353 free_pdu ( Hdr );
2354 break;
2356 break;
2357 default:
2358 /* Unknown state */
2359 free_pdu ( Hdr );
2360 break;
2362 } /* if n > 0 */
2363 } /* if received message */
2364 } /* for each interface */
2365 } /* for ever loop */
2370 main ( int argc, char *argv[] )
2372 int c;
2373 int i;
2374 int Reset = 0; /* Should we send a coldStart and exit? */
2377 * What are we running as? (argv[0])
2379 progname = strdup ( (char *)basename ( argv[0] ) );
2381 * What host are we
2383 gethostname ( hostname, sizeof ( hostname ) );
2386 * Ilmid needs to run as root to set prefix
2388 if ( getuid() != 0 ) {
2389 fprintf ( stderr, "%s: needs to run as root.\n", progname );
2390 exit ( -1 );
2394 * Parse arguments
2396 while ( ( c = getopt ( argc, argv, "d:fr" ) ) != -1 )
2397 switch ( c ) {
2398 case 'd':
2399 Debug_Level = atoi ( optarg );
2400 break;
2401 case 'f':
2402 foregnd++;
2403 break;
2404 case 'r':
2405 Reset++;
2406 break;
2407 case '?':
2408 fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n",
2409 progname );
2410 exit ( -1 );
2411 /* NOTREACHED */
2412 break;
2416 * If we're not doing debugging, run in the background
2418 if ( foregnd == 0 ) {
2419 if ( daemon ( 0, 0 ) )
2420 err ( 1, "Can't fork" );
2423 signal ( SIGUSR1, Increment_DL );
2424 signal ( SIGUSR2, Decrement_DL );
2427 * Open log file
2429 if ( Debug_Level ) {
2430 if ( foregnd ) {
2431 Log = stderr;
2432 } else {
2433 if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL )
2434 Log = NULL;
2437 if ( Log )
2438 setbuf ( Log, NULL );
2441 * Get our startup time
2443 gettimeofday ( &starttime, NULL );
2444 starttime.tv_sec--;
2445 starttime.tv_usec += 1000000;
2447 /* Randomize starting request ID */
2448 Req_ID = starttime.tv_sec;
2451 * Reset all the interface descriptors
2453 for ( i = 0; i < MAX_UNITS; i++ ) {
2454 ilmi_fd[i] = -1;
2457 * Try to open all the interfaces
2459 ilmi_open ();
2462 * If we're just sending a coldStart end exiting...
2464 if ( Reset ) {
2465 for ( i = 0; i < MAX_UNITS; i++ )
2466 if ( ilmi_fd[i] >= 0 ) {
2467 /* Build ColdStart TRAP header */
2468 ColdStart_Header = build_cold_start();
2469 build_pdu ( ColdStart_Header, PDU_TYPE_TRAP );
2470 send_resp ( i, ColdStart_Header, Resp_Buf );
2471 if ( Debug_Level > 1 && Log ) {
2472 write_timestamp();
2473 fprintf ( Log, "Close ilmi_fd[%d]: %d\n",
2474 i, ilmi_fd[i] );
2476 close ( ilmi_fd[i] );
2478 exit ( 2 );
2481 ilmi_do_state();
2483 exit(0);