]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/config.c
warning fixes
[netatalk.git] / etc / atalkd / config.c
1 /*
2  * $Id: config.c,v 1.13.6.1 2004-01-10 08:09:12 bfernhomberg Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved. See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/socket.h>
15 #include <sys/ioctl.h>
16 #include <atalk/logger.h>
17 #include <sys/param.h>
18 #ifdef TRU64
19 #include <sys/mbuf.h>
20 #include <net/route.h>
21 #endif /* TRU64 */
22 #include <net/if.h>
23 #include <netatalk/at.h>
24 #include <netatalk/endian.h>
25 #include <atalk/paths.h>
26 #include <atalk/util.h>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <ctype.h>
33
34 /* STDC check */
35 #if STDC_HEADERS
36 #include <string.h>
37 #else /* STDC_HEADERS */
38 #ifndef HAVE_STRCHR
39 #define strchr index
40 #define strrchr index
41 #endif /* HAVE_STRCHR */
42 char *strchr (), *strrchr ();
43 #ifndef HAVE_MEMCPY
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 */
48
49 #ifdef HAVE_FCNTL_H
50 #include <fcntl.h>
51 #endif /* HAVE_FCNTL_H */
52
53 #ifdef __svr4__
54 #include <sys/sockio.h>
55 #include <sys/stropts.h>
56 #endif /* __svr4__ */
57
58 #include "interface.h"
59 #include "multicast.h"
60 #include "rtmp.h"
61 #include "zip.h"
62 #include "list.h"
63
64 #ifndef IFF_SLAVE /* a little backward compatibility */
65 #define IFF_SLAVE 0
66 #endif /* IFF_SLAVE */
67
68 int     router(), dontroute(), seed(), phase(), net(), addr(), zone();
69
70 static struct param {
71     char        *p_name;
72     int         (*p_func)();
73 } params[] = {
74     { "router", router },
75     { "dontroute", dontroute },
76     { "seed",   seed },
77     { "phase",  phase },
78     { "net",    net },
79     { "addr",   addr },
80     { "zone",   zone },
81 };
82
83 #define ARGV_CHUNK_SIZE 128
84 #define MAXLINELEN 2048
85 char **parseline(const char *line)
86 {
87     const char   *p;
88     int           argc = 0;
89     char         *buffer, *tmpbuf;
90     char        **argv;
91
92     /* Ignore empty lines and lines with leading hash marks. */
93     p = line;
94     while ( isspace( *p ) ) {
95         p++;
96     }
97     if ( *p == '#' || *p == '\0' ) {
98         return NULL;
99     }
100
101     buffer = (char *) malloc( strlen( p ) + 1 );
102     if ( !buffer ) {
103         /* FIXME: error handling */
104         return NULL;
105     }
106     strcpy( buffer, p );
107     tmpbuf = buffer;
108
109     argv = (char **) malloc( ARGV_CHUNK_SIZE * sizeof( char * ) );
110     if ( !argv ) {
111         /* FIXME: error handling */
112         free( buffer );
113         return NULL;
114     }
115
116     /*
117      * This parser should be made more powerful -- it should
118      * handle various escapes, e.g. \" and \031.
119      */
120     do {
121         if ( *tmpbuf == '"' ) {
122             argv[ argc++ ] = ++tmpbuf;
123             while ( *tmpbuf != '\0' && *tmpbuf != '"' ) {
124                 tmpbuf++;
125             }
126             if ( *tmpbuf == '"' ) {
127                 /* FIXME: error handling */
128             }
129         } else {
130             argv[ argc++ ] = tmpbuf;
131             while ( *tmpbuf != '\0' && !isspace( *tmpbuf )) {
132                 tmpbuf++;
133             }
134         }
135         *tmpbuf++ = '\0';
136
137         /* Make room for a NULL pointer and our special pointer (s.b.) */
138         if ( (argc + 1) % ARGV_CHUNK_SIZE == 0 ) {
139             char **tmp;
140             tmp = (char **) realloc( argv, argc + 1 + ARGV_CHUNK_SIZE * sizeof( char * ) );
141             if ( !tmp ) {
142                 /* FIXME: error handling */
143                 free( argv );
144                 free( buffer );
145                 return NULL;
146             }
147             argv = tmp;
148         }
149
150         /* Skip white spaces. */
151         while ( isspace( *tmpbuf ) ) {
152             tmpbuf++;
153         }
154     } while ( *tmpbuf != '\0' );
155
156     argv[ argc++ ] = NULL;
157     /* We store our buffer pointer in argv, too, so we can free it later.
158      * (But don't tell anyone.)
159      */
160     argv[ argc ] = buffer;
161
162     return argv;
163 }
164
165 void freeline( char **argv )
166 {
167     char **tmp = argv;
168
169     if ( argv ) {
170         while ( *tmp ) {
171             tmp++;
172         }
173         free( *++tmp );
174         free( argv );
175     }
176 }
177
178 int writeconf( cf )
179     char        *cf;
180 {
181     struct stat         st;
182     char                *path, *p, newpath[ MAXPATHLEN ], line[ MAXLINELEN ];
183     char                **argv;
184     FILE                *conf, *newconf;
185     struct interface    *iface;
186     struct list         *l;
187     int                 mode = 0644, fd;
188
189     if ( cf == NULL ) {
190         path = _PATH_ATALKDCONF;
191     } else {
192         path = cf;
193     }
194
195     /* check if old conf is writable */
196     if ( stat( path, &st ) == 0 ) {
197         if (( st.st_mode & S_IWUSR ) == 0 ) {
198             LOG(log_info, logtype_atalkd, "%s not writable, won't rewrite", path );
199             return( -1 );
200         }
201          mode = st.st_mode;
202     }
203
204     if (( p = strrchr( path, '/' )) == NULL ) {
205         strcpy( newpath, _PATH_ATALKDTMP );
206     } else {
207         sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP );
208     }
209     if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) {
210         LOG(log_error, logtype_atalkd, "%s: %s", newpath, strerror(errno) );
211         return( -1 );
212     }
213     if (( newconf = fdopen( fd, "w" )) == NULL ) {
214         LOG(log_error, logtype_atalkd, "fdreopen %s: %s", newpath, strerror(errno) );
215         return( -1 );
216     }
217
218     if (( conf = fopen( path, "r" )) == NULL && cf ) {
219         LOG(log_error, logtype_atalkd, "%s: %s", path, strerror(errno) );
220         return( -1 );
221     }
222
223     iface = interfaces->i_next;
224
225     while ( conf == NULL || fgets( line, sizeof( line ), conf ) != NULL ) {
226         if ( conf != NULL && ( argv = parseline( line )) == NULL ) {
227             if ( fputs( line, newconf ) == EOF ) {
228                 LOG(log_error, logtype_atalkd, "fputs: %s", strerror(errno) );
229                 return( -1 );
230             }
231             freeline( argv );
232             continue;
233         }
234
235         /* write real lines */
236         if ( iface ) {
237             fprintf( newconf, "%s", iface->i_name );
238             if ( iface->i_flags & IFACE_RSEED ) {
239                 fprintf( newconf, " -router" );
240             } else if ( iface->i_flags & IFACE_SEED ) {
241                 fprintf( newconf, " -seed" );
242             }
243             if ( iface->i_flags & IFACE_DONTROUTE) {
244                 fprintf( newconf, " -dontroute");
245             }
246
247             fprintf( newconf, " -phase %d",
248                     ( iface->i_flags & IFACE_PHASE1 ) ? 1 : 2 );
249             fprintf( newconf, " -net %d", ntohs( iface->i_rt->rt_firstnet ));
250             if ( iface->i_rt->rt_lastnet != iface->i_rt->rt_firstnet ) {
251                 fprintf( newconf, "-%d", ntohs( iface->i_rt->rt_lastnet ));
252             }
253             fprintf( newconf, " -addr %u.%u",
254                     ntohs( iface->i_addr.sat_addr.s_net ),
255                     iface->i_addr.sat_addr.s_node );
256             for ( l = iface->i_rt->rt_zt; l; l = l->l_next ) {
257                 fprintf( newconf, " -zone \"%.*s\"",
258                         ((struct ziptab *)l->l_data)->zt_len,
259                         ((struct ziptab *)l->l_data)->zt_name );
260             }
261             fprintf( newconf, "\n" );
262
263             iface = iface->i_next;
264             if ( conf == NULL && iface == NULL ) {
265                 break;
266             }
267         }
268     }
269     if ( conf != NULL ) {
270         fclose( conf );
271     }
272     fclose( newconf );
273
274     if ( rename( newpath, path ) < 0 ) {
275         LOG(log_error, logtype_atalkd, "rename %s to %s: %s", newpath, path, strerror(errno) );
276         return( -1 );
277     }
278     return( 0 );
279 }
280
281 /*
282  * Read our config file. If it's not there, return -1. If it is there,
283  * but has syntax errors, exit. Format of the file is as follows:
284  *
285  *      interface [ -seed ] [ -phase number ] [ -net net-range ]
286  *      [ -addr net.node ] [ -zone zonename ]...
287  * e.g.
288  *      le0 -phase 1 -net 7938 -zone Argus
289  * or
290  *      le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems"
291  *      le0 -phase 1 -net 7938 -zone Argus
292  *
293  * Pretty much everything is optional. Anything that is unspecified is
294  * searched for on the network.  If -seed is not specified, the
295  * configuration is assumed to be soft, i.e. it can be overridden by
296  * another router. If -seed is specified, atalkd will exit if another
297  * router disagrees.  If the phase is unspecified, it defaults to phase
298  * 2 (the default can be overridden on the command line).  -addr can
299  * replace -net, if the network in question isn't a range.  The default
300  * zone for an interface is the first zone encountered for that
301  * interface.
302  */
303 int readconf( cf )
304     char                *cf;
305 {
306     struct ifreq        ifr;
307     struct interface    *iface, *niface;
308     char                line[ MAXLINELEN ], **argv, *p;
309     unsigned int        i, j;
310     int                 s, cc;
311     FILE                *conf;
312
313     if ( cf == NULL ) {
314         p = _PATH_ATALKDCONF;
315     } else {
316         p = cf;
317     }
318     if (( conf = fopen( p, "r" )) == NULL ) {
319         return( -1 );
320     }
321
322 #ifndef __svr4__
323     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
324         perror( "socket" );
325         fclose(conf);
326         return -1;
327     }
328 #endif /* __svr4__ */
329
330     while ( fgets( line, sizeof( line ), conf ) != NULL ) {
331         if (( argv = parseline( line )) == NULL ) {
332             continue;
333         }
334
335 #ifndef __svr4__
336         /*
337          * Check that av[ 0 ] is a valid interface.
338          * Not possible under sysV.
339          */
340         strncpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
341         ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
342
343         /* for devices that don't support appletalk */
344         if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
345           perror(argv[0]);
346           goto read_conf_err;
347         }
348
349         if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
350             perror( argv[ 0 ] );
351             goto read_conf_err;
352         }
353
354         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
355             fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
356             goto read_conf_err;
357         }
358
359 #ifdef IFF_MULTICAST
360         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
361             fprintf(stderr, "%s: multicast may not work properly.\n",
362                     ifr.ifr_name);
363 #endif /* IFF_MULTICAST */
364
365         /* configure hw multicast for this interface. */
366         if (addmulti(ifr.ifr_name, NULL) < 0) {
367           perror(ifr.ifr_name);
368           fprintf(stderr, "Can't configure multicast.\n");
369           goto read_conf_err;
370         }
371 #endif /* __svr4__ */
372
373         if (( niface = newiface( argv[ 0 ] )) == NULL ) {
374             perror( "newiface" );
375             goto read_conf_err;
376         }
377
378         for ( i = 1; argv[ i ]; i += cc ) {
379             if ( argv[ i ][ 0 ] == '-' ) {
380                 argv[ i ]++;
381             }
382             for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
383                 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
384                     if ( params[ j ].p_func != NULL ) {
385                         cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
386                         if (cc < 0) 
387                           goto read_conf_err;
388                         break;
389                     }
390                 }
391             }
392             if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
393                 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
394                 goto read_conf_err;
395             }
396         }
397
398         for ( iface = interfaces; iface; iface = iface->i_next ) {
399             if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
400                     ((( niface->i_flags & iface->i_flags &
401                     ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
402                     niface->i_flags == 0 || iface->i_flags == 0 )) {
403                 break;
404             }
405         }
406         if ( iface ) {  /* Already have this interface and phase */
407             fprintf( stderr, "%s already configured!\n", niface->i_name );
408             goto read_conf_err;
409         }
410
411         if ( interfaces == NULL ) {
412             interfaces = niface;
413         } else {
414             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
415                 ;
416             iface->i_next = niface;
417         }
418         niface->i_next = NULL;
419     }
420
421 #ifndef __svr4__
422     close( s );
423 #endif /* __svr4__ */
424
425     fclose( conf );
426
427     /*
428      * Note: we've added lo0 to the interface list previously, so we must
429      * have configured more than one interface...
430      */
431     for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
432         ;
433     if ( cc >= IFBASE ) {
434         return( 0 );
435     } else {
436         return( -1 );
437     }
438
439 read_conf_err:
440 #ifndef __svr4__
441     close(s);
442 #endif /* __svr4__ */
443     fclose(conf);
444     return -1;
445 }
446
447 /*ARGSUSED*/
448 int router( iface, av )
449     struct interface    *iface;
450     char                **av;
451 {
452     /* make sure "-router" and "-dontroute" aren't both on the same line. */
453     if (iface->i_flags & IFACE_DONTROUTE) {
454         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
455         return -1;
456     }
457
458     /*
459      * Check to be sure "-router" is before "-zone".
460      */
461     if ( iface->i_czt ) {
462         fprintf( stderr, "Must specify -router before -zone.\n");
463         return -1;
464     }
465
466     /* -router also implies -seed */
467     iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
468     return( 1 );
469 }
470
471 /*ARGSUSED*/
472 int dontroute( iface, av )
473     struct interface    *iface;
474     char                **av;
475 {
476     /* make sure "-router" and "-dontroute" aren't both on the same line. */
477     if (iface->i_flags & IFACE_RSEED) {
478         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
479         return -1;
480     }
481
482     iface->i_flags |= IFACE_DONTROUTE;
483     return( 1 );
484 }
485
486 /*ARGSUSED*/
487 int seed( iface, av )
488     struct interface    *iface;
489     char                **av;
490 {
491     /*
492      * Check to be sure "-seed" is before "-zone". we keep the old
493      * semantics of just ignoring this in a routerless world.
494      */
495     if ( iface->i_czt ) {
496         fprintf( stderr, "Must specify -seed before -zone(%s).\n",
497                  iface->i_czt->zt_name);
498         return -1;
499     }
500
501     iface->i_flags |= IFACE_SEED;
502     return( 1 );
503 }
504
505 int phase( iface, av )
506     struct interface    *iface;
507     char                **av;
508 {
509     int                 n;
510     char                *pnum;
511
512     if (( pnum = av[ 0 ] ) == NULL ) {
513         fprintf( stderr, "No phase.\n" );
514         return -1;
515     }
516
517     switch ( n = atoi( pnum )) {
518     case 1 :
519         iface->i_flags |= IFACE_PHASE1;
520         break;
521
522     case 2 :
523         iface->i_flags |= IFACE_PHASE2;
524         break;
525
526     default :
527         fprintf( stderr, "No phase %d.\n", n );
528         return -1;
529     }
530     return( 2 );
531 }
532
533 int net( iface, av )
534     struct interface    *iface;
535     char                **av;
536 {
537     char                *nrange;
538     char                *stop;
539     int                 net;
540
541     if (( nrange = av[ 0 ] ) == NULL ) {
542         fprintf( stderr, "No network.\n" );
543         return -1;
544     }
545
546     if (( stop = strchr( nrange, '-' )) != 0 ) {
547         stop++;
548     }
549     net = atoi( nrange );
550     if ( net < 0 || net >= 0xffff ) {
551         fprintf( stderr, "Bad network: %d\n", net );
552         return -1;
553     }
554
555     if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
556         perror( "newrt" );
557         return -1;
558     }
559
560     if ( iface->i_flags & IFACE_PHASE1 ) {
561         if ( stop != 0 ) {
562             fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
563             return -1;
564         }
565         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
566                 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
567             fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
568                     net, ntohs( iface->i_caddr.sat_addr.s_net ));
569             return -1;
570         }
571         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
572     } else if ( iface->i_flags & IFACE_PHASE2 ) {
573         iface->i_rt->rt_firstnet = htons( net );
574         if ( stop != 0 ) {
575             net = atoi( stop );
576             if ( net < 0 || net >= 0xffff ) {
577                 fprintf( stderr, "Bad network: %d\n", net );
578                 return -1;
579             }
580         }
581         iface->i_rt->rt_lastnet = htons( net );
582         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
583                 ( ntohs( iface->i_rt->rt_firstnet ) >
584                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
585                 ntohs( iface->i_rt->rt_lastnet ) <
586                 ntohs( iface->i_caddr.sat_addr.s_net ))) {
587             fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
588                     ntohs( iface->i_rt->rt_firstnet ),
589                     ntohs( iface->i_rt->rt_lastnet ),
590                     ntohs( iface->i_caddr.sat_addr.s_net ));
591             return -1;
592         }
593         if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
594             iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
595         }
596     } else {
597         fprintf( stderr, "Must specify phase before networks.\n" );
598         return -1;
599     }
600     return( 2 );
601 }
602
603 int addr( iface, av )
604     struct interface    *iface;
605     char                **av;
606 {
607     if ( av[ 0 ] == NULL ) {
608         fprintf( stderr, "No address.\n" );
609         return -1;
610     }
611     if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
612         fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
613         return -1;
614     }
615
616     if ( iface->i_rt ) {
617         if ( ntohs( iface->i_rt->rt_firstnet ) >
618                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
619                 ntohs( iface->i_rt->rt_lastnet ) <
620                 ntohs( iface->i_caddr.sat_addr.s_net )) {
621             fprintf( stderr, "Net (%u) not in net-range (%u-%u).\n",
622                     ntohs( iface->i_caddr.sat_addr.s_net ),
623                     ntohs( iface->i_rt->rt_firstnet ),
624                     ntohs( iface->i_rt->rt_lastnet ));
625             return -1;
626         }
627     } else {
628         if (( iface->i_rt = newrt(iface)) == NULL ) {
629             perror( "newrt" );
630             return -1;
631         }
632         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
633                 iface->i_caddr.sat_addr.s_net;
634     }
635
636     return( 2 );
637 }
638
639 int zone( iface, av )
640     struct interface    *iface;
641     char                **av;
642 {
643     struct ziptab       *zt;
644     char                *zname;
645
646     if (( zname = av[ 0 ] ) == NULL ) {
647         fprintf( stderr, "No zone.\n" );
648         return -1;
649     }
650
651     /*
652      * Only process "-zone" if this interface has "-seed".  We keep our
653      * list of configured zones in the interface structure.  Then we can
654      * check that the network has given us good zones.
655      */
656     if ( iface->i_flags & IFACE_SEED ) {
657         if ( iface->i_rt == NULL ) {
658             fprintf( stderr, "Must specify net-range before zones.\n" );
659             return -1;
660         }
661         if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
662             perror( "newzt" );
663             return -1;
664         }
665         if ( iface->i_czt == NULL ) {
666             iface->i_czt = zt;
667         } else {
668             zt->zt_next = iface->i_czt->zt_next;
669             iface->i_czt->zt_next = zt;
670         }
671     }
672     return( 2 );
673 }
674
675 /*
676  * Get the configuration from the kernel. Only called if there's no
677  * configuration.
678  */
679 int getifconf()
680 {
681     struct interface    *iface, *niface;
682     struct ifreq        ifr;
683     char                **start, **list;
684     int                 s;
685
686     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
687         perror( "socket" );
688         return -1;
689     }
690
691     start = list = getifacelist();
692     while (list && *list) {
693         strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
694         list++;
695
696         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
697           continue;
698
699         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
700           continue;
701
702         if ((ifr.ifr_flags & IFF_UP) == 0)
703           continue;
704
705         /* for devices that don't support appletalk */
706         if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
707           continue;
708
709         for ( iface = interfaces; iface; iface = iface->i_next ) {
710             if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
711                 break;
712             }
713         }
714         if ( iface ) {  /* Already have this interface name */
715             continue;
716         }
717
718
719 #ifdef IFF_MULTICAST
720         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
721           fprintf(stderr, "%s: multicast may not work correctly.\n",
722                   ifr.ifr_name);
723 #endif /* IFF_MULTICAST */
724
725         if (addmulti(ifr.ifr_name, NULL) < 0) {
726           fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
727           continue;
728         }
729         
730         if (( niface = newiface( ifr.ifr_name )) == NULL ) {
731             perror( "newiface" );
732             close(s);
733             freeifacelist(start);
734             return -1;
735         }
736         /*
737          * Could try to get the address from the kernel...
738          */
739
740         if ( interfaces == NULL ) {
741             interfaces = niface;
742         } else {
743             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
744                 ;
745             iface->i_next = niface;
746         }
747         niface->i_next = NULL;
748     }
749     freeifacelist(start);
750     (void)close( s );
751     return( 0 );
752 }
753
754 /*
755  * Allocate a new interface structure.  Centralized here so we can change
756  * the interface structure and have it updated nicely.
757  */
758
759 struct interface *newiface( name )
760     const char          *name;
761 {
762     struct interface    *niface;
763
764     if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
765             == NULL ) {
766         return( NULL );
767     }
768     strncpy( niface->i_name, name, sizeof(niface->i_name));
769 #ifdef BSD4_4
770     niface->i_addr.sat_len = sizeof( struct sockaddr_at );
771 #endif /* BSD4_4 */
772     niface->i_addr.sat_family = AF_APPLETALK;
773 #ifdef BSD4_4
774     niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
775 #endif /* BSD4_4 */
776     niface->i_caddr.sat_family = AF_APPLETALK;
777     return( niface );
778 }
779
780 #ifdef __svr4__
781 int plumb()
782 {
783     struct interface    *iface;
784     char                device[ MAXPATHLEN + 1], *p;
785     int                 fd, ppa;
786
787     for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
788         if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
789             continue;
790         }
791
792         strcpy( device, "/dev/" );
793         strcat( device, iface->i_name );
794         if (( p = strpbrk( device, "0123456789" )) == NULL ) {
795             LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device );
796             return -1;
797         }
798         ppa = atoi( p );
799         *p = '\0';
800
801         if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
802             LOG(log_error, logtype_atalkd, "%s: %m", device );
803             return -1;
804         }
805         if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
806             LOG(log_error, logtype_atalkd, "I_PUSH: %m" );
807             close(fd);
808             return -1;
809         }
810         if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
811             LOG(log_error, logtype_atalkd, "IF_UNITSEL: %m" );
812             close(fd);
813             return -1;
814         }
815
816         /* configure multicast. */
817         if (addmulti(iface->i_name, NULL) < 0) {
818           perror(iface->i_name);
819           fprintf(stderr,"Can't configure multicast.\n");
820           close(fd);
821           return -1;
822         }
823
824         LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
825     }
826
827     return( 0 );
828 }
829 #endif /* __svr4__ */