2 * $Id: config.c,v 1.7 2001-12-10 20:16:55 srittau 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>
36 #else /* STDC_HEADERS */
40 #endif /* HAVE_STRCHR */
41 char *strchr (), *strrchr ();
43 #define memcpy(d,s,n) bcopy ((s), (d), (n))
44 #define memmove(d,s,n) bcopy ((s), (d), (n))
45 #endif /* ! HAVE_MEMCPY */
46 #endif /* STDC_HEADERS */
50 #endif /* HAVE_FCNTL_H */
53 #include <sys/sockio.h>
54 #include <sys/stropts.h>
57 #include "interface.h"
58 #include "multicast.h"
63 #ifndef IFF_SLAVE /* a little backward compatibility */
65 #endif /* IFF_SLAVE */
67 int router(), dontroute(), seed(), phase(), net(), addr(), zone();
74 { "dontroute", dontroute },
88 static char *argv[ 128 ];
89 static char buf[ 1024 ];
96 memset(argv, 0, sizeof(argv));
101 * This parser should be made more powerful -- it should
102 * handle various escapes, e.g. \" and \031.
104 while ( *p != '\0' ) {
105 while ( *p != '\0' && *p != '"' && isspace( *p )) {
114 while ( *p != '\0' && *p != '"' ) {
119 while ( *p != '\0' && !isspace( *p )) {
126 if ( argv[ 0 ] == '\0' || *argv[ 0 ] == '#' ) {
136 char *path, *p, newpath[ MAXPATHLEN ], line[ 1024 ];
138 FILE *conf, *newconf;
139 struct interface *iface;
144 path = _PATH_ATALKDCONF;
149 /* check if old conf is writable */
150 if ( stat( path, &st ) == 0 ) {
151 if (( st.st_mode & S_IWUSR ) == 0 ) {
152 syslog( LOG_INFO, "%s not writable, won't rewrite", path );
158 if (( p = strrchr( path, '/' )) == NULL ) {
159 strcpy( newpath, _PATH_ATALKDTMP );
161 sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
163 if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
164 syslog( LOG_ERR, "%s: %s", newpath, strerror(errno) );
167 if (( newconf = fdopen( fd, "w" )) == NULL ) {
168 syslog( LOG_ERR, "fdreopen %s: %s", newpath, strerror(errno) );
172 if (( conf = fopen( path, "r" )) == NULL && cf ) {
173 syslog( LOG_ERR, "%s: %s", path, strerror(errno) );
177 iface = interfaces->i_next;
179 while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
180 if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
181 if ( fputs( line, newconf ) == EOF ) {
182 syslog( LOG_ERR, "fputs: %s", strerror(errno) );
188 /* write real lines */
190 fprintf( newconf, "%s", iface->i_name );
191 if ( iface->i_flags & IFACE_RSEED ) {
192 fprintf( newconf, " -router" );
193 } else if ( iface->i_flags & IFACE_SEED ) {
194 fprintf( newconf, " -seed" );
196 if ( iface->i_flags & IFACE_DONTROUTE) {
197 fprintf( newconf, " -dontroute");
200 fprintf( newconf, " -phase %d",
201 ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
202 fprintf( newconf, " -net %d", ntohs( iface->i_rt->rt_firstnet ));
203 if ( iface->i_rt->rt_lastnet != iface->i_rt->rt_firstnet ) {
204 fprintf( newconf, "-%d", ntohs( iface->i_rt->rt_lastnet ));
206 fprintf( newconf, " -addr %u.%u",
207 ntohs( iface->i_addr.sat_addr.s_net ),
208 iface->i_addr.sat_addr.s_node );
209 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
210 fprintf( newconf, " -zone \"%.*s\"",
211 ((struct ziptab *)l->l_data)->zt_len,
212 ((struct ziptab *)l->l_data)->zt_name );
214 fprintf( newconf, "\n" );
216 iface = iface->i_next;
217 if ( conf == NULL && iface == NULL ) {
222 if ( conf != NULL ) {
227 if ( rename( newpath, path ) < 0 ) {
228 syslog( LOG_ERR, "rename %s to %s: %s", newpath, path, strerror(errno) );
235 * Read our config file. If it's not there, return -1. If it is there,
236 * but has syntax errors, exit. Format of the file is as follows:
238 * interface [ -seed ] [ -phase number ] [ -net net-range ]
239 * [ -addr net.node ] [ -zone zonename ]...
241 * le0 -phase 1 -net 7938 -zone Argus
243 * le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems"
244 * le0 -phase 1 -net 7938 -zone Argus
246 * Pretty much everything is optional. Anything that is unspecified is
247 * searched for on the network. If -seed is not specified, the
248 * configuration is assumed to be soft, i.e. it can be overridden by
249 * another router. If -seed is specified, atalkd will exit if another
250 * router disagrees. If the phase is unspecified, it defaults to phase
251 * 2 (the default can be overridden on the command line). -addr can
252 * replace -net, if the network in question isn't a range. The default
253 * zone for an interface is the first zone encountered for that
260 struct interface *iface, *niface;
261 char line[ 1024 ], **argv, *p;
266 p = _PATH_ATALKDCONF;
270 if (( conf = fopen( p, "r" )) == NULL ) {
275 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
280 #endif /* __svr4__ */
282 while ( fgets( line, sizeof( line ), conf ) != NULL ) {
283 if (( argv = parseline( line )) == NULL ) {
289 * Check that av[ 0 ] is a valid interface.
290 * Not possible under sysV.
292 strcpy( ifr.ifr_name, argv[ 0 ] );
294 /* for devices that don't support appletalk */
295 if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
300 if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
305 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
306 fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
311 if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
312 fprintf(stderr, "%s: multicast may not work properly.\n",
314 #endif /* IFF_MULTICAST */
316 /* configure hw multicast for this interface. */
317 if (addmulti(ifr.ifr_name, NULL) < 0) {
318 perror(ifr.ifr_name);
319 fprintf(stderr, "Can't configure multicast.\n");
322 #endif /* __svr4__ */
324 if (( niface = newiface( argv[ 0 ] )) == NULL ) {
325 perror( "newiface" );
329 for ( i = 1; argv[ i ]; i += cc ) {
330 if ( argv[ i ][ 0 ] == '-' ) {
333 for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
334 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
335 if ( params[ j ].p_func != NULL ) {
336 cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
343 if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
344 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
349 for ( iface = interfaces; iface; iface = iface->i_next ) {
350 if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
351 ((( niface->i_flags & iface->i_flags &
352 ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
353 niface->i_flags == 0 || iface->i_flags == 0 )) {
357 if ( iface ) { /* Already have this interface and phase */
358 fprintf( stderr, "%s already configured!\n", niface->i_name );
362 if ( interfaces == NULL ) {
365 for ( iface = interfaces; iface->i_next; iface = iface->i_next )
367 iface->i_next = niface;
369 niface->i_next = NULL;
374 #endif /* __svr4__ */
379 * Note: we've added lo0 to the interface list previously, so we must
380 * have configured more than one interface...
382 for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
384 if ( cc >= IFBASE ) {
393 #endif /* __svr4__ */
399 int router( iface, av )
400 struct interface *iface;
403 /* make sure "-router" and "-dontroute" aren't both on the same line. */
404 if (iface->i_flags & IFACE_DONTROUTE) {
405 fprintf( stderr, "Can't specify both -router and -dontroute.\n");
410 * Check to be sure "-router" is before "-zone".
412 if ( iface->i_czt ) {
413 fprintf( stderr, "Must specify -router before -zone.\n");
417 /* -router also implies -seed */
418 iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
423 int dontroute( iface, av )
424 struct interface *iface;
427 /* make sure "-router" and "-dontroute" aren't both on the same line. */
428 if (iface->i_flags & IFACE_RSEED) {
429 fprintf( stderr, "Can't specify both -router and -dontroute.\n");
433 iface->i_flags |= IFACE_DONTROUTE;
438 int seed( iface, av )
439 struct interface *iface;
443 * Check to be sure "-seed" is before "-zone". we keep the old
444 * semantics of just ignoring this in a routerless world.
446 if ( iface->i_czt ) {
447 fprintf( stderr, "Must specify -seed before -zone(%s).\n",
448 iface->i_czt->zt_name);
452 iface->i_flags |= IFACE_SEED;
456 int phase( iface, av )
457 struct interface *iface;
463 if (( pnum = av[ 0 ] ) == NULL ) {
464 fprintf( stderr, "No phase.\n" );
468 switch ( n = atoi( pnum )) {
470 iface->i_flags |= IFACE_PHASE1;
474 iface->i_flags |= IFACE_PHASE2;
478 fprintf( stderr, "No phase %d.\n", n );
485 struct interface *iface;
492 if (( nrange = av[ 0 ] ) == NULL ) {
493 fprintf( stderr, "No network.\n" );
497 if (( stop = strchr( nrange, '-' )) != 0 ) {
500 net = atoi( nrange );
501 if ( net < 0 || net >= 0xffff ) {
502 fprintf( stderr, "Bad network: %d\n", net );
506 if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
511 if ( iface->i_flags & IFACE_PHASE1 ) {
513 fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
516 if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
517 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
518 fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
519 net, ntohs( iface->i_caddr.sat_addr.s_net ));
522 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
523 } else if ( iface->i_flags & IFACE_PHASE2 ) {
524 iface->i_rt->rt_firstnet = htons( net );
527 if ( net < 0 || net >= 0xffff ) {
528 fprintf( stderr, "Bad network: %d\n", net );
532 iface->i_rt->rt_lastnet = htons( net );
533 if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
534 ( ntohs( iface->i_rt->rt_firstnet ) >
535 ntohs( iface->i_caddr.sat_addr.s_net ) ||
536 ntohs( iface->i_rt->rt_lastnet ) <
537 ntohs( iface->i_caddr.sat_addr.s_net ))) {
538 fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
539 ntohs( iface->i_rt->rt_firstnet ),
540 ntohs( iface->i_rt->rt_lastnet ),
541 ntohs( iface->i_caddr.sat_addr.s_net ));
544 if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
545 iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
548 fprintf( stderr, "Must specify phase before networks.\n" );
554 int addr( iface, av )
555 struct interface *iface;
558 if ( av[ 0 ] == NULL ) {
559 fprintf( stderr, "No address.\n" );
562 if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
563 fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
568 if ( ntohs( iface->i_rt->rt_firstnet ) >
569 ntohs( iface->i_caddr.sat_addr.s_net ) ||
570 ntohs( iface->i_rt->rt_lastnet ) <
571 ntohs( iface->i_caddr.sat_addr.s_net )) {
572 fprintf( stderr, "Net (%u) not in net-range (%u-%u).\n",
573 ntohs( iface->i_caddr.sat_addr.s_net ),
574 ntohs( iface->i_rt->rt_firstnet ),
575 ntohs( iface->i_rt->rt_lastnet ));
579 if (( iface->i_rt = newrt(iface)) == NULL ) {
583 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
584 iface->i_caddr.sat_addr.s_net;
590 int zone( iface, av )
591 struct interface *iface;
597 if (( zname = av[ 0 ] ) == NULL ) {
598 fprintf( stderr, "No zone.\n" );
603 * Only process "-zone" if this interface has "-seed". We keep our
604 * list of configured zones in the interface structure. Then we can
605 * check that the network has given us good zones.
607 if ( iface->i_flags & IFACE_SEED ) {
608 if ( iface->i_rt == NULL ) {
609 fprintf( stderr, "Must specify net-range before zones.\n" );
612 if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
616 if ( iface->i_czt == NULL ) {
619 zt->zt_next = iface->i_czt->zt_next;
620 iface->i_czt->zt_next = zt;
627 * Get the configuration from the kernel. Only called if there's no
632 struct interface *iface, *niface;
634 char **start, **list;
637 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
642 start = list = getifacelist();
643 while (list && *list) {
644 strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
647 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
650 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
653 if ((ifr.ifr_flags & IFF_UP) == 0)
656 /* for devices that don't support appletalk */
657 if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
660 for ( iface = interfaces; iface; iface = iface->i_next ) {
661 if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
665 if ( iface ) { /* Already have this interface name */
671 if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
672 fprintf(stderr, "%s: multicast may not work correctly.\n",
674 #endif /* IFF_MULTICAST */
676 if (addmulti(ifr.ifr_name, NULL) < 0) {
677 fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
681 if (( niface = newiface( ifr.ifr_name )) == NULL ) {
682 perror( "newiface" );
684 freeifacelist(start);
688 * Could try to get the address from the kernel...
691 if ( interfaces == NULL ) {
694 for ( iface = interfaces; iface->i_next; iface = iface->i_next )
696 iface->i_next = niface;
698 niface->i_next = NULL;
700 freeifacelist(start);
706 * Allocate a new interface structure. Centralized here so we can change
707 * the interface structure and have it updated nicely.
710 struct interface *newiface( name )
713 struct interface *niface;
715 if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
719 strncpy( niface->i_name, name, sizeof(niface->i_name));
721 niface->i_addr.sat_len = sizeof( struct sockaddr_at );
723 niface->i_addr.sat_family = AF_APPLETALK;
725 niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
727 niface->i_caddr.sat_family = AF_APPLETALK;
734 struct interface *iface;
735 char device[ MAXPATHLEN + 1], *p;
738 for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
739 if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
743 strcpy( device, "/dev/" );
744 strcat( device, iface->i_name );
745 if (( p = strpbrk( device, "0123456789" )) == NULL ) {
746 syslog( LOG_ERR, "plumb: invalid device: %s", device );
752 if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
753 syslog( LOG_ERR, "%s: %m", device );
756 if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
757 syslog( LOG_ERR, "I_PUSH: %m" );
761 if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
762 syslog( LOG_ERR, "IF_UNITSEL: %m" );
767 /* configure multicast. */
768 if (addmulti(iface->i_name, NULL) < 0) {
769 perror(iface->i_name);
770 fprintf(stderr,"Can't configure multicast.\n");
775 syslog( LOG_INFO, "plumbed %s%d", device, ppa );
780 #endif /* __svr4__ */