]> arthur.barton.de Git - netatalk.git/blob - etc/atalkd/config.c
parseline(): Increase buffer size instead of shrinking it, in case the
[netatalk.git] / etc / atalkd / config.c
1 /*
2  * $Id: config.c,v 1.13 2003-03-18 23:32:17 srittau 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     int                 i, j, s, cc;
310     FILE                *conf;
311
312     if ( cf == NULL ) {
313         p = _PATH_ATALKDCONF;
314     } else {
315         p = cf;
316     }
317     if (( conf = fopen( p, "r" )) == NULL ) {
318         return( -1 );
319     }
320
321 #ifndef __svr4__
322     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
323         perror( "socket" );
324         fclose(conf);
325         return -1;
326     }
327 #endif /* __svr4__ */
328
329     while ( fgets( line, sizeof( line ), conf ) != NULL ) {
330         if (( argv = parseline( line )) == NULL ) {
331             continue;
332         }
333
334 #ifndef __svr4__
335         /*
336          * Check that av[ 0 ] is a valid interface.
337          * Not possible under sysV.
338          */
339         strncpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) );
340         ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
341
342         /* for devices that don't support appletalk */
343         if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) {
344           perror(argv[0]);
345           goto read_conf_err;
346         }
347
348         if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) {
349             perror( argv[ 0 ] );
350             goto read_conf_err;
351         }
352
353         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) {
354             fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name );
355             goto read_conf_err;
356         }
357
358 #ifdef IFF_MULTICAST
359         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
360             fprintf(stderr, "%s: multicast may not work properly.\n",
361                     ifr.ifr_name);
362 #endif /* IFF_MULTICAST */
363
364         /* configure hw multicast for this interface. */
365         if (addmulti(ifr.ifr_name, NULL) < 0) {
366           perror(ifr.ifr_name);
367           fprintf(stderr, "Can't configure multicast.\n");
368           goto read_conf_err;
369         }
370 #endif /* __svr4__ */
371
372         if (( niface = newiface( argv[ 0 ] )) == NULL ) {
373             perror( "newiface" );
374             goto read_conf_err;
375         }
376
377         for ( i = 1; argv[ i ]; i += cc ) {
378             if ( argv[ i ][ 0 ] == '-' ) {
379                 argv[ i ]++;
380             }
381             for ( j = 0; j < sizeof( params ) / sizeof( params[ 0 ] ); j++ ) {
382                 if ( strcmp( argv[ i ], params[ j ].p_name ) == 0 ) {
383                     if ( params[ j ].p_func != NULL ) {
384                         cc = (*params[ j ].p_func)( niface, &argv[ i + 1 ] );
385                         if (cc < 0) 
386                           goto read_conf_err;
387                         break;
388                     }
389                 }
390             }
391             if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) {
392                 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] );
393                 goto read_conf_err;
394             }
395         }
396
397         for ( iface = interfaces; iface; iface = iface->i_next ) {
398             if ( strcmp( niface->i_name, iface->i_name ) == 0 &&
399                     ((( niface->i_flags & iface->i_flags &
400                     ( IFACE_PHASE1|IFACE_PHASE2 )) != 0 ) ||
401                     niface->i_flags == 0 || iface->i_flags == 0 )) {
402                 break;
403             }
404         }
405         if ( iface ) {  /* Already have this interface and phase */
406             fprintf( stderr, "%s already configured!\n", niface->i_name );
407             goto read_conf_err;
408         }
409
410         if ( interfaces == NULL ) {
411             interfaces = niface;
412         } else {
413             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
414                 ;
415             iface->i_next = niface;
416         }
417         niface->i_next = NULL;
418     }
419
420 #ifndef __svr4__
421     close( s );
422 #endif /* __svr4__ */
423
424     fclose( conf );
425
426     /*
427      * Note: we've added lo0 to the interface list previously, so we must
428      * have configured more than one interface...
429      */
430     for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ )
431         ;
432     if ( cc >= IFBASE ) {
433         return( 0 );
434     } else {
435         return( -1 );
436     }
437
438 read_conf_err:
439 #ifndef __svr4__
440     close(s);
441 #endif /* __svr4__ */
442     fclose(conf);
443     return -1;
444 }
445
446 /*ARGSUSED*/
447 int router( iface, av )
448     struct interface    *iface;
449     char                **av;
450 {
451     /* make sure "-router" and "-dontroute" aren't both on the same line. */
452     if (iface->i_flags & IFACE_DONTROUTE) {
453         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
454         return -1;
455     }
456
457     /*
458      * Check to be sure "-router" is before "-zone".
459      */
460     if ( iface->i_czt ) {
461         fprintf( stderr, "Must specify -router before -zone.\n");
462         return -1;
463     }
464
465     /* -router also implies -seed */
466     iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER;
467     return( 1 );
468 }
469
470 /*ARGSUSED*/
471 int dontroute( iface, av )
472     struct interface    *iface;
473     char                **av;
474 {
475     /* make sure "-router" and "-dontroute" aren't both on the same line. */
476     if (iface->i_flags & IFACE_RSEED) {
477         fprintf( stderr, "Can't specify both -router and -dontroute.\n");
478         return -1;
479     }
480
481     iface->i_flags |= IFACE_DONTROUTE;
482     return( 1 );
483 }
484
485 /*ARGSUSED*/
486 int seed( iface, av )
487     struct interface    *iface;
488     char                **av;
489 {
490     /*
491      * Check to be sure "-seed" is before "-zone". we keep the old
492      * semantics of just ignoring this in a routerless world.
493      */
494     if ( iface->i_czt ) {
495         fprintf( stderr, "Must specify -seed before -zone(%s).\n",
496                  iface->i_czt->zt_name);
497         return -1;
498     }
499
500     iface->i_flags |= IFACE_SEED;
501     return( 1 );
502 }
503
504 int phase( iface, av )
505     struct interface    *iface;
506     char                **av;
507 {
508     int                 n;
509     char                *pnum;
510
511     if (( pnum = av[ 0 ] ) == NULL ) {
512         fprintf( stderr, "No phase.\n" );
513         return -1;
514     }
515
516     switch ( n = atoi( pnum )) {
517     case 1 :
518         iface->i_flags |= IFACE_PHASE1;
519         break;
520
521     case 2 :
522         iface->i_flags |= IFACE_PHASE2;
523         break;
524
525     default :
526         fprintf( stderr, "No phase %d.\n", n );
527         return -1;
528     }
529     return( 2 );
530 }
531
532 int net( iface, av )
533     struct interface    *iface;
534     char                **av;
535 {
536     char                *nrange;
537     char                *stop;
538     int                 net;
539
540     if (( nrange = av[ 0 ] ) == NULL ) {
541         fprintf( stderr, "No network.\n" );
542         return -1;
543     }
544
545     if (( stop = strchr( nrange, '-' )) != 0 ) {
546         stop++;
547     }
548     net = atoi( nrange );
549     if ( net < 0 || net >= 0xffff ) {
550         fprintf( stderr, "Bad network: %d\n", net );
551         return -1;
552     }
553
554     if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) {
555         perror( "newrt" );
556         return -1;
557     }
558
559     if ( iface->i_flags & IFACE_PHASE1 ) {
560         if ( stop != 0 ) {
561             fprintf( stderr, "Phase 1 doesn't use an address range.\n" );
562             return -1;
563         }
564         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
565                 ntohs( iface->i_caddr.sat_addr.s_net ) != net ) {
566             fprintf( stderr, "Net-range (%u) doesn't match net %u.\n",
567                     net, ntohs( iface->i_caddr.sat_addr.s_net ));
568             return -1;
569         }
570         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = htons( net );
571     } else if ( iface->i_flags & IFACE_PHASE2 ) {
572         iface->i_rt->rt_firstnet = htons( net );
573         if ( stop != 0 ) {
574             net = atoi( stop );
575             if ( net < 0 || net >= 0xffff ) {
576                 fprintf( stderr, "Bad network: %d\n", net );
577                 return -1;
578             }
579         }
580         iface->i_rt->rt_lastnet = htons( net );
581         if ( iface->i_caddr.sat_addr.s_net != ATADDR_ANYNET &&
582                 ( ntohs( iface->i_rt->rt_firstnet ) >
583                 ntohs( iface->i_caddr.sat_addr.s_net ) ||
584                 ntohs( iface->i_rt->rt_lastnet ) <
585                 ntohs( iface->i_caddr.sat_addr.s_net ))) {
586             fprintf( stderr, "Net-range (%u-%u) doesn't contain net (%u).\n",
587                     ntohs( iface->i_rt->rt_firstnet ),
588                     ntohs( iface->i_rt->rt_lastnet ),
589                     ntohs( iface->i_caddr.sat_addr.s_net ));
590             return -1;
591         }
592         if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) {
593             iface->i_rt->rt_flags |= RTMPTAB_EXTENDED;
594         }
595     } else {
596         fprintf( stderr, "Must specify phase before networks.\n" );
597         return -1;
598     }
599     return( 2 );
600 }
601
602 int addr( iface, av )
603     struct interface    *iface;
604     char                **av;
605 {
606     if ( av[ 0 ] == NULL ) {
607         fprintf( stderr, "No address.\n" );
608         return -1;
609     }
610     if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) {
611         fprintf( stderr, "Bad address, %s\n", av[ 0 ] );
612         return -1;
613     }
614
615     if ( iface->i_rt ) {
616         if ( 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 (%u) not in net-range (%u-%u).\n",
621                     ntohs( iface->i_caddr.sat_addr.s_net ),
622                     ntohs( iface->i_rt->rt_firstnet ),
623                     ntohs( iface->i_rt->rt_lastnet ));
624             return -1;
625         }
626     } else {
627         if (( iface->i_rt = newrt(iface)) == NULL ) {
628             perror( "newrt" );
629             return -1;
630         }
631         iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet =
632                 iface->i_caddr.sat_addr.s_net;
633     }
634
635     return( 2 );
636 }
637
638 int zone( iface, av )
639     struct interface    *iface;
640     char                **av;
641 {
642     struct ziptab       *zt;
643     char                *zname;
644
645     if (( zname = av[ 0 ] ) == NULL ) {
646         fprintf( stderr, "No zone.\n" );
647         return -1;
648     }
649
650     /*
651      * Only process "-zone" if this interface has "-seed".  We keep our
652      * list of configured zones in the interface structure.  Then we can
653      * check that the network has given us good zones.
654      */
655     if ( iface->i_flags & IFACE_SEED ) {
656         if ( iface->i_rt == NULL ) {
657             fprintf( stderr, "Must specify net-range before zones.\n" );
658             return -1;
659         }
660         if (( zt = newzt( strlen( zname ), zname )) == NULL ) {
661             perror( "newzt" );
662             return -1;
663         }
664         if ( iface->i_czt == NULL ) {
665             iface->i_czt = zt;
666         } else {
667             zt->zt_next = iface->i_czt->zt_next;
668             iface->i_czt->zt_next = zt;
669         }
670     }
671     return( 2 );
672 }
673
674 /*
675  * Get the configuration from the kernel. Only called if there's no
676  * configuration.
677  */
678 int getifconf()
679 {
680     struct interface    *iface, *niface;
681     struct ifreq        ifr;
682     char                **start, **list;
683     int                 s;
684
685     if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) {
686         perror( "socket" );
687         return -1;
688     }
689
690     start = list = getifacelist();
691     while (list && *list) {
692         strncpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name));
693         list++;
694
695         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
696           continue;
697
698         if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE))
699           continue;
700
701         if ((ifr.ifr_flags & IFF_UP) == 0)
702           continue;
703
704         /* for devices that don't support appletalk */
705         if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV))
706           continue;
707
708         for ( iface = interfaces; iface; iface = iface->i_next ) {
709             if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) {
710                 break;
711             }
712         }
713         if ( iface ) {  /* Already have this interface name */
714             continue;
715         }
716
717
718 #ifdef IFF_MULTICAST
719         if ((ifr.ifr_flags & IFF_MULTICAST) == 0)
720           fprintf(stderr, "%s: multicast may not work correctly.\n",
721                   ifr.ifr_name);
722 #endif /* IFF_MULTICAST */
723
724         if (addmulti(ifr.ifr_name, NULL) < 0) {
725           fprintf(stderr, "%s: disabled.\n", ifr.ifr_name);
726           continue;
727         }
728         
729         if (( niface = newiface( ifr.ifr_name )) == NULL ) {
730             perror( "newiface" );
731             close(s);
732             freeifacelist(start);
733             return -1;
734         }
735         /*
736          * Could try to get the address from the kernel...
737          */
738
739         if ( interfaces == NULL ) {
740             interfaces = niface;
741         } else {
742             for ( iface = interfaces; iface->i_next; iface = iface->i_next )
743                 ;
744             iface->i_next = niface;
745         }
746         niface->i_next = NULL;
747     }
748     freeifacelist(start);
749     (void)close( s );
750     return( 0 );
751 }
752
753 /*
754  * Allocate a new interface structure.  Centralized here so we can change
755  * the interface structure and have it updated nicely.
756  */
757
758 struct interface *newiface( name )
759     const char          *name;
760 {
761     struct interface    *niface;
762
763     if (( niface = (struct interface *)calloc(1, sizeof( struct interface )))
764             == NULL ) {
765         return( NULL );
766     }
767     strncpy( niface->i_name, name, sizeof(niface->i_name));
768 #ifdef BSD4_4
769     niface->i_addr.sat_len = sizeof( struct sockaddr_at );
770 #endif /* BSD4_4 */
771     niface->i_addr.sat_family = AF_APPLETALK;
772 #ifdef BSD4_4
773     niface->i_caddr.sat_len = sizeof( struct sockaddr_at );
774 #endif /* BSD4_4 */
775     niface->i_caddr.sat_family = AF_APPLETALK;
776     return( niface );
777 }
778
779 #ifdef __svr4__
780 int plumb()
781 {
782     struct interface    *iface;
783     char                device[ MAXPATHLEN + 1], *p;
784     int                 fd, ppa;
785
786     for ( iface = interfaces; iface != NULL; iface = iface->i_next ) {
787         if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) {
788             continue;
789         }
790
791         strcpy( device, "/dev/" );
792         strcat( device, iface->i_name );
793         if (( p = strpbrk( device, "0123456789" )) == NULL ) {
794             LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device );
795             return -1;
796         }
797         ppa = atoi( p );
798         *p = '\0';
799
800         if (( fd = open( device, O_RDWR, 0 )) < 0 ) {
801             LOG(log_error, logtype_atalkd, "%s: %m", device );
802             return -1;
803         }
804         if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) {
805             LOG(log_error, logtype_atalkd, "I_PUSH: %m" );
806             close(fd);
807             return -1;
808         }
809         if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) {
810             LOG(log_error, logtype_atalkd, "IF_UNITSEL: %m" );
811             close(fd);
812             return -1;
813         }
814
815         /* configure multicast. */
816         if (addmulti(iface->i_name, NULL) < 0) {
817           perror(iface->i_name);
818           fprintf(stderr,"Can't configure multicast.\n");
819           close(fd);
820           return -1;
821         }
822
823         LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa );
824     }
825
826     return( 0 );
827 }
828 #endif /* __svr4__ */