2 * $Id: config.c,v 1.20 2009-10-29 11:35:58 didg 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>
16 #include <atalk/logger.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>
37 #else /* STDC_HEADERS */
41 #endif /* HAVE_STRCHR */
42 char *strchr (), *strrchr ();
44 #define memcpy(d,s,n) bcopy ((s), (d), (n))
45 #define memmove(d,s,n) bcopy ((s), (d), (n))
46 #endif /* ! HAVE_MEMCPY */
47 #endif /* STDC_HEADERS */
51 #endif /* HAVE_FCNTL_H */
54 #include <sys/sockio.h>
55 #include <sys/stropts.h>
58 #include <atalk/unicode.h>
59 #include "interface.h"
60 #include "multicast.h"
66 #ifndef IFF_SLAVE /* a little backward compatibility */
68 #endif /* IFF_SLAVE */
70 int router(struct interface *iface, char **av);
71 int dontroute(struct interface *iface, char **av);
72 int seed(struct interface *iface, char **av);
73 int phase(struct interface *iface, char **av);
74 int net(struct interface *iface, char **av);
75 int addr(struct interface *iface, char **av);
76 int zone(struct interface *iface, char **av);
77 int noallmulti(struct interface *iface, char **av);
79 static const struct param {
81 int (*p_func)(struct interface *iface, char **av);
84 { "dontroute", dontroute },
90 { "noallmulti", noallmulti }
93 #define ARGV_CHUNK_SIZE 128
94 #define MAXLINELEN 2048
95 static char **parseline(const char *line)
99 char *buffer, *tmpbuf;
102 /* Ignore empty lines and lines with leading hash marks. */
104 while ( isspace( *p ) ) {
107 if ( *p == '#' || *p == '\0' ) {
111 buffer = (char *) malloc( strlen( p ) + 1 );
113 /* FIXME: error handling */
119 argv = (char **) malloc( ARGV_CHUNK_SIZE * sizeof( char * ) );
121 /* FIXME: error handling */
127 * This parser should be made more powerful -- it should
128 * handle various escapes, e.g. \" and \031.
131 if ( *tmpbuf == '"' ) {
132 argv[ argc++ ] = ++tmpbuf;
133 while ( *tmpbuf != '\0' && *tmpbuf != '"' ) {
136 if ( *tmpbuf == '"' ) {
137 /* FIXME: error handling */
140 argv[ argc++ ] = tmpbuf;
141 while ( *tmpbuf != '\0' && !isspace( *tmpbuf )) {
147 /* Make room for a NULL pointer and our special pointer (s.b.) */
148 if ( (argc + 1) % ARGV_CHUNK_SIZE == 0 ) {
150 tmp = (char **) realloc( argv, argc + 1 + ARGV_CHUNK_SIZE * sizeof( char * ) );
152 /* FIXME: error handling */
160 /* Skip white spaces. */
161 while ( isspace( *tmpbuf ) ) {
164 } while ( *tmpbuf != '\0' );
166 argv[ argc++ ] = NULL;
167 /* We store our buffer pointer in argv, too, so we can free it later.
168 * (But don't tell anyone.)
170 argv[ argc ] = buffer;
175 static void freeline( char **argv )
188 int writeconf(char *cf)
191 char *path, *p, newpath[ MAXPATHLEN ], line[ MAXLINELEN ];
193 FILE *conf, *newconf;
194 struct interface *iface;
201 path = _PATH_ATALKDCONF;
206 /* check if old conf is writable */
207 if ( stat( path, &st ) == 0 ) {
208 if (( st.st_mode & S_IWUSR ) == 0 ) {
209 LOG(log_info, logtype_atalkd, "%s not writable, won't rewrite", path );
215 if (( p = strrchr( path, '/' )) == NULL ) {
216 strcpy( newpath, _PATH_ATALKDTMP );
218 sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
220 if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
221 LOG(log_error, logtype_atalkd, "%s: %s", newpath, strerror(errno) );
224 if (( newconf = fdopen( fd, "w" )) == NULL ) {
225 LOG(log_error, logtype_atalkd, "fdreopen %s: %s", newpath, strerror(errno) );
229 if (( conf = fopen( path, "r" )) == NULL && cf ) {
230 LOG(log_error, logtype_atalkd, "%s: %s", path, strerror(errno) );
234 iface = interfaces->i_next;
236 while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
237 if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
238 if ( fputs( line, newconf ) == EOF ) {
239 LOG(log_error, logtype_atalkd, "fputs: %s", strerror(errno) );
246 /* write real lines */
248 fprintf( newconf, "%s", iface->i_name );
249 if ( iface->i_flags & IFACE_RSEED ) {
250 fprintf( newconf, " -router" );
251 } else if ( iface->i_flags & IFACE_SEED ) {
252 fprintf( newconf, " -seed" );
254 if ( iface->i_flags & IFACE_DONTROUTE) {
255 fprintf( newconf, " -dontroute");
258 if ( !(iface->i_flags & IFACE_ALLMULTI)) {
259 fprintf( newconf, " -noallmulti");
263 fprintf( newconf, " -phase %d",
264 ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
265 fprintf( newconf, " -net %d", ntohs( iface->i_rt->rt_firstnet ));
266 if ( iface->i_rt->rt_lastnet != iface->i_rt->rt_firstnet ) {
267 fprintf( newconf, "-%d", ntohs( iface->i_rt->rt_lastnet ));
269 fprintf( newconf, " -addr %u.%u",
270 ntohs( iface->i_addr.sat_addr.s_net ),
271 iface->i_addr.sat_addr.s_node );
272 for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
273 /* codepage conversion */
274 if ((size_t)(-1) == (len = convert_string_allocate(CH_MAC, CH_UNIX,
275 ((struct ziptab *)l->l_data)->zt_name,
276 ((struct ziptab *)l->l_data)->zt_len,
279 (zonename = strdup(((struct ziptab *)l->l_data)->zt_name))) {
280 LOG(log_error, logtype_atalkd, "malloc: %s", strerror(errno) );
283 len = ((struct ziptab *)l->l_data)->zt_len;
285 fprintf( newconf, " -zone \"%.*s\"", (int)len, zonename);
288 fprintf( newconf, "\n" );
290 iface = iface->i_next;
291 if ( conf == NULL && iface == NULL ) {
296 if ( conf != NULL ) {
301 if ( rename( newpath, path ) < 0 ) {
302 LOG(log_error, logtype_atalkd, "rename %s to %s: %s", newpath, path, strerror(errno) );
309 * Read our config file. If it's not there, return -1. If it is there,
310 * but has syntax errors, exit. Format of the file is as follows:
312 * interface [ -seed ] [ -phase number ] [ -net net-range ]
313 * [ -addr net.node ] [ -zone zonename ]...
315 * le0 -phase 1 -net 7938 -zone Argus
317 * le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems"
318 * le0 -phase 1 -net 7938 -zone Argus
320 * Pretty much everything is optional. Anything that is unspecified is
321 * searched for on the network. If -seed is not specified, the
322 * configuration is assumed to be soft, i.e. it can be overridden by
323 * another router. If -seed is specified, atalkd will exit if another
324 * router disagrees. If the phase is unspecified, it defaults to phase
325 * 2 (the default can be overridden on the command line). -addr can
326 * replace -net, if the network in question isn't a range. The default
327 * zone for an interface is the first zone encountered for that
330 int readconf(char *cf)
333 struct interface *iface, *niface;
334 char line[ MAXLINELEN ], **argv, *p;
340 p = _PATH_ATALKDCONF;
344 if (( conf = fopen( p, "r" )) == NULL ) {
349 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
354 #endif /* __svr4__ */
356 while ( fgets( line, sizeof( line ), conf ) != NULL ) {
357 if (( argv = parseline( line )) == NULL ) {
363 * Check that av[ 0 ] is a valid interface.
364 * Not possible under sysV.
366 strlcpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
368 /* for devices that don't support appletalk */
369 if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
374 if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
379 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
380 fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
385 if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
386 fprintf(stderr, "%s: multicast may not work properly.\n",
388 #endif /* IFF_MULTICAST */
390 /* configure hw multicast for this interface. */
391 if (addmulti(ifr.ifr_name, NULL) < 0) {
392 perror(ifr.ifr_name);
393 fprintf(stderr, "Can't configure multicast.\n");
397 #endif /* __svr4__ */
399 if (( niface = newiface( argv[ 0 ] )) == NULL ) {
400 perror( "newiface" );
404 for ( i = 1; argv[ i ]; i += cc ) {
405 if ( argv[ i ][ 0 ] == '-' ) {
408 for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
409 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
410 if ( params[ j ].p_func != NULL ) {
411 cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
418 if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
419 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
424 for ( iface = interfaces; iface; iface = iface->i_next ) {
425 if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
426 ((( niface->i_flags & iface->i_flags &
427 ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
428 niface->i_flags == 0 || iface->i_flags == 0 )) {
432 if ( iface ) { /* Already have this interface and phase */
433 fprintf( stderr, "%s already configured!\n", niface->i_name );
438 /* Don't set interface to allmulti if it already is, or -noallmulti was given */
439 if ((ifr.ifr_flags & IFF_ALLMULTI))
440 niface->i_flags |= IFACE_WASALLMULTI;
442 if ((niface->i_flags & IFACE_ALLMULTI) && !(niface->i_flags & IFACE_WASALLMULTI))
443 ifsetallmulti(ifr.ifr_name, 1);
446 if ( interfaces == NULL ) {
449 for ( iface = interfaces; iface->i_next; iface = iface->i_next )
451 iface->i_next = niface;
453 niface->i_next = NULL;
458 #endif /* __svr4__ */
463 * Note: we've added lo0 to the interface list previously, so we must
464 * have configured more than one interface...
466 for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
468 if ( cc >= IFBASE ) {
477 #endif /* __svr4__ */
482 int noallmulti( struct interface *iface, char **av _U_)
484 /* Linux specific, no effect on other platforms */
485 iface->i_flags &= !IFACE_ALLMULTI;
491 int router(struct interface *iface, char **av _U_)
493 /* make sure "-router" and "-dontroute" aren't both on the same line. */
494 if (iface->i_flags & IFACE_DONTROUTE) {
495 fprintf( stderr, "Can't specify both -router and -dontroute.\n");
500 * Check to be sure "-router" is before "-zone".
502 if ( iface->i_czt ) {
503 fprintf( stderr, "Must specify -router before -zone.\n");
507 /* -router also implies -seed */
508 iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
513 int dontroute(struct interface *iface, char **av _U_)
515 /* make sure "-router" and "-dontroute" aren't both on the same line. */
516 if (iface->i_flags & IFACE_RSEED) {
517 fprintf( stderr, "Can't specify both -router and -dontroute.\n");
521 iface->i_flags |= IFACE_DONTROUTE;
526 int seed( struct interface *iface, char **av _U_)
529 * Check to be sure "-seed" is before "-zone". we keep the old
530 * semantics of just ignoring this in a routerless world.
532 if ( iface->i_czt ) {
533 fprintf( stderr, "Must specify -seed before -zone(%s).\n",
534 iface->i_czt->zt_name);
538 iface->i_flags |= IFACE_SEED;
542 int phase(struct interface *iface, char **av)
547 if (( pnum = av[ 0 ] ) == NULL ) {
548 fprintf( stderr, "No phase.\n" );
552 switch ( n = atoi( pnum )) {
554 iface->i_flags |= IFACE_PHASE1;
558 iface->i_flags |= IFACE_PHASE2;
562 fprintf( stderr, "No phase %d.\n", n );
568 int net(struct interface *iface, char **av)
574 if (( nrange = av[ 0 ] ) == NULL ) {
575 fprintf( stderr, "No network.\n" );
579 if (( stop = strchr( nrange, '-' )) != NULL ) {
582 net = atoi( nrange );
583 if ( net < 0 || net >= 0xffff ) {
584 fprintf( stderr, "Bad network: %d\n", net );
588 if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
593 if ( iface->i_flags & IFACE_PHASE1 ) {
594 if ( stop != NULL ) {
595 fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
598 if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
599 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
600 fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
601 net, ntohs( iface->i_caddr.sat_addr.s_net ));
604 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
605 } else if ( iface->i_flags & IFACE_PHASE2 ) {
606 iface->i_rt->rt_firstnet = htons( net );
607 if ( stop != NULL ) {
609 if ( net < 0 || net >= 0xffff ) {
610 fprintf( stderr, "Bad network: %d\n", net );
614 iface->i_rt->rt_lastnet = htons( net );
615 if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
616 ( ntohs( iface->i_rt->rt_firstnet ) >
617 ntohs( iface->i_caddr.sat_addr.s_net ) ||
618 ntohs( iface->i_rt->rt_lastnet ) <
619 ntohs( iface->i_caddr.sat_addr.s_net ))) {
620 fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
621 ntohs( iface->i_rt->rt_firstnet ),
622 ntohs( iface->i_rt->rt_lastnet ),
623 ntohs( iface->i_caddr.sat_addr.s_net ));
626 if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
627 iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
630 fprintf( stderr, "Must specify phase before networks.\n" );
636 int addr(struct interface *iface, char **av)
638 if ( av[ 0 ] == NULL ) {
639 fprintf( stderr, "No address.\n" );
642 if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
643 fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
648 if ( ntohs( iface->i_rt->rt_firstnet ) >
649 ntohs( iface->i_caddr.sat_addr.s_net ) ||
650 ntohs( iface->i_rt->rt_lastnet ) <
651 ntohs( iface->i_caddr.sat_addr.s_net )) {
652 fprintf( stderr, "Net (%u) not in net-range (%u-%u).\n",
653 ntohs( iface->i_caddr.sat_addr.s_net ),
654 ntohs( iface->i_rt->rt_firstnet ),
655 ntohs( iface->i_rt->rt_lastnet ));
659 if (( iface->i_rt = newrt(iface)) == NULL ) {
663 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
664 iface->i_caddr.sat_addr.s_net;
670 int zone(struct interface *iface, char **av)
675 if ( av[ 0 ] == NULL ) {
676 fprintf( stderr, "No zone.\n" );
680 /* codepage conversion */
681 if ((size_t)(-1) == convert_string_allocate(CH_UNIX, CH_MAC, av[0], -1, &zname)) {
682 zname = strdup(av[0]);
686 * Only process "-zone" if this interface has "-seed". We keep our
687 * list of configured zones in the interface structure. Then we can
688 * check that the network has given us good zones.
690 if ( iface->i_flags & IFACE_SEED ) {
691 if ( iface->i_rt == NULL ) {
692 fprintf( stderr, "Must specify net-range before zones.\n" );
696 if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
700 if ( iface->i_czt == NULL ) {
703 zt->zt_next = iface->i_czt->zt_next;
704 iface->i_czt->zt_next = zt;
713 * Get the configuration from the kernel. Only called if there's no
718 struct interface *iface, *niface;
720 char **start, **list;
723 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
728 start = list = getifacelist();
729 while (list && *list) {
730 strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
733 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
736 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
739 if ((ifr.ifr_flags & IFF_UP) == 0)
742 /* for devices that don't support appletalk */
743 if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
746 for ( iface = interfaces; iface; iface = iface->i_next ) {
747 if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
751 if ( iface ) { /* Already have this interface name */
757 if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
758 fprintf(stderr, "%s: multicast may not work correctly.\n",
760 #endif /* IFF_MULTICAST */
762 if (addmulti(ifr.ifr_name, NULL) < 0) {
763 fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
767 if (( niface = newiface( ifr.ifr_name )) == NULL ) {
768 perror( "newiface" );
770 freeifacelist(start);
774 * Could try to get the address from the kernel...
777 if ( interfaces == NULL ) {
780 for ( iface = interfaces; iface->i_next; iface = iface->i_next )
782 iface->i_next = niface;
784 niface->i_next = NULL;
786 freeifacelist(start);
792 * Allocate a new interface structure. Centralized here so we can change
793 * the interface structure and have it updated nicely.
796 struct interface *newiface( const char *name)
798 struct interface *niface;
800 if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
804 strlcpy( niface->i_name, name, sizeof(niface->i_name));
806 niface->i_addr.sat_len = sizeof( struct sockaddr_at );
808 niface->i_addr.sat_family = AF_APPLETALK;
810 niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
812 niface->i_caddr.sat_family = AF_APPLETALK;
814 niface->i_flags = IFACE_ALLMULTI;
822 struct interface *iface;
823 char device[ MAXPATHLEN + 1], *p, *t;
827 for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
828 if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
832 strcpy( device, "/dev/" );
833 strcat( device, iface->i_name );
834 for (t = device; *t != '\0' ; ++t) {
835 if (isdigit(*t) == 0) {
844 LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device );
850 if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
851 LOG(log_error, logtype_atalkd, "%s: %s", device, strerror(errno) );
854 if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
855 LOG(log_error, logtype_atalkd, "I_PUSH: %s", strerror(errno) );
859 if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
860 LOG(log_error, logtype_atalkd, "IF_UNITSEL: %s", strerror(errno) );
865 /* configure multicast. */
866 if (addmulti(iface->i_name, NULL) < 0) {
867 perror(iface->i_name);
868 fprintf(stderr,"Can't configure multicast.\n");
873 LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
880 #endif /* __svr4__ */