2 * $Id: config.c,v 1.6 2001-09-06 20:00:59 rufustfirefly Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* HAVE_CONFIG_H */
12 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
17 #include <sys/param.h>
20 #include <net/route.h>
23 #include <netatalk/at.h>
24 #include <netatalk/endian.h>
25 #include <atalk/paths.h>
26 #include <atalk/util.h>
33 #else /* STDC_HEADERS */
37 #endif /* HAVE_STRCHR */
38 char *strchr (), *strrchr ();
40 #define memcpy(d,s,n) bcopy ((s), (d), (n))
41 #define memmove(d,s,n) bcopy ((s), (d), (n))
42 #endif /* ! HAVE_MEMCPY */
43 #endif /* STDC_HEADERS */
48 #endif /* HAVE_FCNTL_H */
52 #include <sys/sockio.h>
53 #include <sys/stropts.h>
56 #include "interface.h"
57 #include "multicast.h"
62 #ifndef IFF_SLAVE /* a little backward compatibility */
64 #endif /* IFF_SLAVE */
66 int router(), dontroute(), seed(), phase(), net(), addr(), zone();
73 { "dontroute", dontroute },
87 static char *argv[ 128 ];
88 static char buf[ 1024 ];
95 memset(argv, 0, sizeof(argv));
100 * This parser should be made more powerful -- it should
101 * handle various escapes, e.g. \" and \031.
103 while ( *p != '\0' ) {
104 while ( *p != '\0' && *p != '"' && isspace( *p )) {
113 while ( *p != '\0' && *p != '"' ) {
118 while ( *p != '\0' && !isspace( *p )) {
125 if ( argv[ 0 ] == '\0' || *argv[ 0 ] == '#' ) {
135 char *path, *p, newpath[ MAXPATHLEN ], line[ 1024 ];
137 FILE *conf, *newconf;
138 struct interface *iface;
143 path = _PATH_ATALKDCONF;
148 /* check if old conf is writable */
149 if ( stat( path, &st ) == 0 ) {
150 if (( st.st_mode & S_IWUSR ) == 0 ) {
151 syslog( LOG_INFO, "%s not writable, won't rewrite", path );
157 if (( p = strrchr( path, '/' )) == NULL ) {
158 strcpy( newpath, _PATH_ATALKDTMP );
160 sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
162 if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
163 syslog( LOG_ERR, "%s: %m", newpath );
166 if (( newconf = fdopen( fd, "w" )) == NULL ) {
167 syslog( LOG_ERR, "fdreopen %s: %m", newpath );
171 if (( conf = fopen( path, "r" )) == NULL && cf ) {
172 syslog( LOG_ERR, "%s: %m", path );
176 iface = interfaces->i_next;
178 while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
179 if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
180 if ( fputs( line, newconf ) == EOF ) {
181 syslog( LOG_ERR, "fputs: %m" );
187 /* write real lines */
189 fprintf( newconf, "%s", iface->i_name );
190 if ( iface->i_flags & IFACE_RSEED ) {
191 fprintf( newconf, " -router" );
192 } else if ( iface->i_flags & IFACE_SEED ) {
193 fprintf( newconf, " -seed" );
195 if ( iface->i_flags & IFACE_DONTROUTE) {
196 fprintf( newconf, " -dontroute");
199 fprintf( newconf, " -phase %d",
200 ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
201 fprintf( newconf, " -net %d", ntohs( iface->i_rt->rt_firstnet ));
202 if ( iface->i_rt->rt_lastnet != iface->i_rt->rt_firstnet ) {
203 fprintf( newconf, "-%d", ntohs( iface->i_rt->rt_lastnet ));
205 fprintf( newconf, " -addr %u.%u",
206 ntohs( iface->i_addr.sat_addr.s_net ),
207 iface->i_addr.sat_addr.s_node );
208 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
209 fprintf( newconf, " -zone \"%.*s\"",
210 ((struct ziptab *)l->l_data)->zt_len,
211 ((struct ziptab *)l->l_data)->zt_name );
213 fprintf( newconf, "\n" );
215 iface = iface->i_next;
216 if ( conf == NULL && iface == NULL ) {
221 if ( conf != NULL ) {
226 if ( rename( newpath, path ) < 0 ) {
227 syslog( LOG_ERR, "rename %s to %s: %m", newpath, path );
234 * Read our config file. If it's not there, return -1. If it is there,
235 * but has syntax errors, exit. Format of the file is as follows:
237 * interface [ -seed ] [ -phase number ] [ -net net-range ]
238 * [ -addr net.node ] [ -zone zonename ]...
240 * le0 -phase 1 -net 7938 -zone Argus
242 * le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems"
243 * le0 -phase 1 -net 7938 -zone Argus
245 * Pretty much everything is optional. Anything that is unspecified is
246 * searched for on the network. If -seed is not specified, the
247 * configuration is assumed to be soft, i.e. it can be overridden by
248 * another router. If -seed is specified, atalkd will exit if another
249 * router disagrees. If the phase is unspecified, it defaults to phase
250 * 2 (the default can be overridden on the command line). -addr can
251 * replace -net, if the network in question isn't a range. The default
252 * zone for an interface is the first zone encountered for that
259 struct interface *iface, *niface;
260 char line[ 1024 ], **argv, *p;
265 p = _PATH_ATALKDCONF;
269 if (( conf = fopen( p, "r" )) == NULL ) {
274 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
279 #endif /* __svr4__ */
281 while ( fgets( line, sizeof( line ), conf ) != NULL ) {
282 if (( argv = parseline( line )) == NULL ) {
288 * Check that av[ 0 ] is a valid interface.
289 * Not possible under sysV.
291 strcpy( ifr.ifr_name, argv[ 0 ] );
293 /* for devices that don't support appletalk */
294 if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
299 if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
304 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
305 fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
310 if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
311 fprintf(stderr, "%s: multicast may not work properly.\n",
313 #endif /* IFF_MULTICAST */
315 /* configure hw multicast for this interface. */
316 if (addmulti(ifr.ifr_name, NULL) < 0) {
317 perror(ifr.ifr_name);
318 fprintf(stderr, "Can't configure multicast.\n");
321 #endif /* __svr4__ */
323 if (( niface = newiface( argv[ 0 ] )) == NULL ) {
324 perror( "newiface" );
328 for ( i = 1; argv[ i ]; i += cc ) {
329 if ( argv[ i ][ 0 ] == '-' ) {
332 for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
333 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
334 if ( params[ j ].p_func != NULL ) {
335 cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
342 if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
343 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
348 for ( iface = interfaces; iface; iface = iface->i_next ) {
349 if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
350 ((( niface->i_flags & iface->i_flags &
351 ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
352 niface->i_flags == 0 || iface->i_flags == 0 )) {
356 if ( iface ) { /* Already have this interface and phase */
357 fprintf( stderr, "%s already configured!\n", niface->i_name );
361 if ( interfaces == NULL ) {
364 for ( iface = interfaces; iface->i_next; iface = iface->i_next )
366 iface->i_next = niface;
368 niface->i_next = NULL;
373 #endif /* __svr4__ */
378 * Note: we've added lo0 to the interface list previously, so we must
379 * have configured more than one interface...
381 for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
383 if ( cc >= IFBASE ) {
392 #endif /* __svr4__ */
398 int router( iface, av )
399 struct interface *iface;
402 /* make sure "-router" and "-dontroute" aren't both on the same line. */
403 if (iface->i_flags & IFACE_DONTROUTE) {
404 fprintf( stderr, "Can't specify both -router and -dontroute.\n");
409 * Check to be sure "-router" is before "-zone".
411 if ( iface->i_czt ) {
412 fprintf( stderr, "Must specify -router before -zone.\n");
416 /* -router also implies -seed */
417 iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
422 int dontroute( iface, av )
423 struct interface *iface;
426 /* make sure "-router" and "-dontroute" aren't both on the same line. */
427 if (iface->i_flags & IFACE_RSEED) {
428 fprintf( stderr, "Can't specify both -router and -dontroute.\n");
432 iface->i_flags |= IFACE_DONTROUTE;
437 int seed( iface, av )
438 struct interface *iface;
442 * Check to be sure "-seed" is before "-zone". we keep the old
443 * semantics of just ignoring this in a routerless world.
445 if ( iface->i_czt ) {
446 fprintf( stderr, "Must specify -seed before -zone(%s).\n",
447 iface->i_czt->zt_name);
451 iface->i_flags |= IFACE_SEED;
455 int phase( iface, av )
456 struct interface *iface;
462 if (( pnum = av[ 0 ] ) == NULL ) {
463 fprintf( stderr, "No phase.\n" );
467 switch ( n = atoi( pnum )) {
469 iface->i_flags |= IFACE_PHASE1;
473 iface->i_flags |= IFACE_PHASE2;
477 fprintf( stderr, "No phase %d.\n", n );
484 struct interface *iface;
491 if (( nrange = av[ 0 ] ) == NULL ) {
492 fprintf( stderr, "No network.\n" );
496 if (( stop = strchr( nrange, '-' )) != 0 ) {
499 net = atoi( nrange );
500 if ( net < 0 || net >= 0xffff ) {
501 fprintf( stderr, "Bad network: %d\n", net );
505 if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
510 if ( iface->i_flags & IFACE_PHASE1 ) {
512 fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
515 if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
516 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
517 fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
518 net, ntohs( iface->i_caddr.sat_addr.s_net ));
521 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
522 } else if ( iface->i_flags & IFACE_PHASE2 ) {
523 iface->i_rt->rt_firstnet = htons( net );
526 if ( net < 0 || net >= 0xffff ) {
527 fprintf( stderr, "Bad network: %d\n", net );
531 iface->i_rt->rt_lastnet = htons( net );
532 if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
533 ( ntohs( iface->i_rt->rt_firstnet ) >
534 ntohs( iface->i_caddr.sat_addr.s_net ) ||
535 ntohs( iface->i_rt->rt_lastnet ) <
536 ntohs( iface->i_caddr.sat_addr.s_net ))) {
537 fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
538 ntohs( iface->i_rt->rt_firstnet ),
539 ntohs( iface->i_rt->rt_lastnet ),
540 ntohs( iface->i_caddr.sat_addr.s_net ));
543 if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
544 iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
547 fprintf( stderr, "Must specify phase before networks.\n" );
553 int addr( iface, av )
554 struct interface *iface;
557 if ( av[ 0 ] == NULL ) {
558 fprintf( stderr, "No address.\n" );
561 if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
562 fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
567 if ( ntohs( iface->i_rt->rt_firstnet ) >
568 ntohs( iface->i_caddr.sat_addr.s_net ) ||
569 ntohs( iface->i_rt->rt_lastnet ) <
570 ntohs( iface->i_caddr.sat_addr.s_net )) {
571 fprintf( stderr, "Net (%u) not in net-range (%u-%u).\n",
572 ntohs( iface->i_caddr.sat_addr.s_net ),
573 ntohs( iface->i_rt->rt_firstnet ),
574 ntohs( iface->i_rt->rt_lastnet ));
578 if (( iface->i_rt = newrt(iface)) == NULL ) {
582 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
583 iface->i_caddr.sat_addr.s_net;
589 int zone( iface, av )
590 struct interface *iface;
596 if (( zname = av[ 0 ] ) == NULL ) {
597 fprintf( stderr, "No zone.\n" );
602 * Only process "-zone" if this interface has "-seed". We keep our
603 * list of configured zones in the interface structure. Then we can
604 * check that the network has given us good zones.
606 if ( iface->i_flags & IFACE_SEED ) {
607 if ( iface->i_rt == NULL ) {
608 fprintf( stderr, "Must specify net-range before zones.\n" );
611 if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
615 if ( iface->i_czt == NULL ) {
618 zt->zt_next = iface->i_czt->zt_next;
619 iface->i_czt->zt_next = zt;
626 * Get the configuration from the kernel. Only called if there's no
631 struct interface *iface, *niface;
633 char **start, **list;
636 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
641 start = list = getifacelist();
642 while (list && *list) {
643 strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
646 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
649 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
652 if ((ifr.ifr_flags & IFF_UP) == 0)
655 /* for devices that don't support appletalk */
656 if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
659 for ( iface = interfaces; iface; iface = iface->i_next ) {
660 if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
664 if ( iface ) { /* Already have this interface name */
670 if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
671 fprintf(stderr, "%s: multicast may not work correctly.\n",
673 #endif /* IFF_MULTICAST */
675 if (addmulti(ifr.ifr_name, NULL) < 0) {
676 fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
680 if (( niface = newiface( ifr.ifr_name )) == NULL ) {
681 perror( "newiface" );
683 freeifacelist(start);
687 * Could try to get the address from the kernel...
690 if ( interfaces == NULL ) {
693 for ( iface = interfaces; iface->i_next; iface = iface->i_next )
695 iface->i_next = niface;
697 niface->i_next = NULL;
699 freeifacelist(start);
705 * Allocate a new interface structure. Centralized here so we can change
706 * the interface structure and have it updated nicely.
709 struct interface *newiface( name )
712 struct interface *niface;
714 if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
718 strncpy( niface->i_name, name, sizeof(niface->i_name));
720 niface->i_addr.sat_len = sizeof( struct sockaddr_at );
722 niface->i_addr.sat_family = AF_APPLETALK;
724 niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
726 niface->i_caddr.sat_family = AF_APPLETALK;
733 struct interface *iface;
734 char device[ MAXPATHLEN + 1], *p;
737 for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
738 if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
742 strcpy( device, "/dev/" );
743 strcat( device, iface->i_name );
744 if (( p = strpbrk( device, "0123456789" )) == NULL ) {
745 syslog( LOG_ERR, "plumb: invalid device: %s", device );
751 if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
752 syslog( LOG_ERR, "%s: %m", device );
755 if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
756 syslog( LOG_ERR, "I_PUSH: %m" );
760 if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
761 syslog( LOG_ERR, "IF_UNITSEL: %m" );
766 /* configure multicast. */
767 if (addmulti(iface->i_name, NULL) < 0) {
768 perror(iface->i_name);
769 fprintf(stderr,"Can't configure multicast.\n");
774 syslog( LOG_INFO, "plumbed %s%d", device, ppa );
779 #endif /* __svr4__ */