1/* 2 * $Id: config.c,v 1.20 2009-10-29 11:35:58 didg 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 */ 42char *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 <atalk/unicode.h> 59#include "interface.h" 60#include "multicast.h" 61#include "rtmp.h" 62#include "zip.h" 63#include "list.h" 64#include "main.h" 65 66#ifndef IFF_SLAVE /* a little backward compatibility */ 67#define IFF_SLAVE 0 68#endif /* IFF_SLAVE */ 69 70int router(struct interface *iface, char **av); 71int dontroute(struct interface *iface, char **av); 72int seed(struct interface *iface, char **av); 73int phase(struct interface *iface, char **av); 74int net(struct interface *iface, char **av); 75int addr(struct interface *iface, char **av); 76int zone(struct interface *iface, char **av); 77int noallmulti(struct interface *iface, char **av); 78 79static const struct param { 80 char *p_name; 81 int (*p_func)(struct interface *iface, char **av); 82} params[] = { 83 { "router", router }, 84 { "dontroute", dontroute }, 85 { "seed", seed }, 86 { "phase", phase }, 87 { "net", net }, 88 { "addr", addr }, 89 { "zone", zone }, 90 { "noallmulti", noallmulti } 91}; 92 93#define ARGV_CHUNK_SIZE 128 94#define MAXLINELEN 2048 95static char **parseline(const char *line) 96{ 97 const char *p; 98 int argc = 0; 99 char *buffer, *tmpbuf; 100 char **argv; 101 102 /* Ignore empty lines and lines with leading hash marks. */ 103 p = line; 104 while ( isspace( *p ) ) { 105 p++; 106 } 107 if ( *p == '#' || *p == '\0' ) { 108 return NULL; 109 } 110 111 buffer = (char *) malloc( strlen( p ) + 1 ); 112 if ( !buffer ) { 113 /* FIXME: error handling */ 114 return NULL; 115 } 116 strcpy( buffer, p ); 117 tmpbuf = buffer; 118 119 argv = (char **) malloc( ARGV_CHUNK_SIZE * sizeof( char * ) ); 120 if ( !argv ) { 121 /* FIXME: error handling */ 122 free( buffer ); 123 return NULL; 124 } 125 126 /* 127 * This parser should be made more powerful -- it should 128 * handle various escapes, e.g. \" and \031. 129 */ 130 do { 131 if ( *tmpbuf == '"' ) { 132 argv[ argc++ ] = ++tmpbuf; 133 while ( *tmpbuf != '\0' && *tmpbuf != '"' ) { 134 tmpbuf++; 135 } 136 if ( *tmpbuf == '"' ) { 137 /* FIXME: error handling */ 138 } 139 } else { 140 argv[ argc++ ] = tmpbuf; 141 while ( *tmpbuf != '\0' && !isspace( *tmpbuf )) { 142 tmpbuf++; 143 } 144 } 145 *tmpbuf++ = '\0'; 146 147 /* Make room for a NULL pointer and our special pointer (s.b.) */ 148 if ( (argc + 1) % ARGV_CHUNK_SIZE == 0 ) { 149 char **tmp; 150 tmp = (char **) realloc( argv, argc + 1 + ARGV_CHUNK_SIZE * sizeof( char * ) ); 151 if ( !tmp ) { 152 /* FIXME: error handling */ 153 free( argv ); 154 free( buffer ); 155 return NULL; 156 } 157 argv = tmp; 158 } 159 160 /* Skip white spaces. */ 161 while ( isspace( *tmpbuf ) ) { 162 tmpbuf++; 163 } 164 } while ( *tmpbuf != '\0' ); 165 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.) 169 */ 170 argv[ argc ] = buffer; 171 172 return argv; 173} 174 175static void freeline( char **argv ) 176{ 177 char **tmp = argv; 178 179 if ( argv ) { 180 while ( *tmp ) { 181 tmp++; 182 } 183 free( *++tmp ); 184 free( argv ); 185 } 186} 187 188int writeconf(char *cf) 189{ 190 struct stat st; 191 char *path, *p, newpath[ MAXPATHLEN ], line[ MAXLINELEN ]; 192 char **argv; 193 FILE *conf, *newconf; 194 struct interface *iface; 195 struct list *l; 196 int mode = 0644, fd; 197 size_t len; 198 char *zonename; 199 200 if ( cf == NULL ) { 201 path = _PATH_ATALKDCONF; 202 } else { 203 path = cf; 204 } 205 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 ); 210 return( -1 ); 211 } 212 mode = st.st_mode; 213 } 214 215 if (( p = strrchr( path, '/' )) == NULL ) { 216 strcpy( newpath, _PATH_ATALKDTMP ); 217 } else { 218 sprintf( newpath, "%.*s/%s", (int)(p - path), path, _PATH_ATALKDTMP ); 219 } 220 if (( fd = open( newpath, O_WRONLY|O_CREAT|O_TRUNC, mode )) < 0 ) { 221 LOG(log_error, logtype_atalkd, "%s: %s", newpath, strerror(errno) ); 222 return( -1 ); 223 } 224 if (( newconf = fdopen( fd, "w" )) == NULL ) { 225 LOG(log_error, logtype_atalkd, "fdreopen %s: %s", newpath, strerror(errno) ); 226 return( -1 ); 227 } 228 229 if (( conf = fopen( path, "r" )) == NULL && cf ) { 230 LOG(log_error, logtype_atalkd, "%s: %s", path, strerror(errno) ); 231 return( -1 ); 232 } 233 234 iface = interfaces->i_next; 235 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) ); 240 return( -1 ); 241 } 242 freeline( argv ); 243 continue; 244 } 245 246 /* write real lines */ 247 if ( iface ) { 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" ); 253 } 254 if ( iface->i_flags & IFACE_DONTROUTE) { 255 fprintf( newconf, " -dontroute"); 256 } 257#ifdef linux 258 if ( !(iface->i_flags & IFACE_ALLMULTI)) { 259 fprintf( newconf, " -noallmulti"); 260 } 261#endif 262 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 )); 268 } 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, 277 &zonename)) ) { 278 if ( NULL == 279 (zonename = strdup(((struct ziptab *)l->l_data)->zt_name))) { 280 LOG(log_error, logtype_atalkd, "malloc: %s", strerror(errno) ); 281 return( -1 ); 282 } 283 len = ((struct ziptab *)l->l_data)->zt_len; 284 } 285 fprintf( newconf, " -zone \"%.*s\"", (int)len, zonename); 286 free(zonename); 287 } 288 fprintf( newconf, "\n" ); 289 290 iface = iface->i_next; 291 if ( conf == NULL && iface == NULL ) { 292 break; 293 } 294 } 295 } 296 if ( conf != NULL ) { 297 fclose( conf ); 298 } 299 fclose( newconf ); 300 301 if ( rename( newpath, path ) < 0 ) { 302 LOG(log_error, logtype_atalkd, "rename %s to %s: %s", newpath, path, strerror(errno) ); 303 return( -1 ); 304 } 305 return( 0 ); 306} 307 308/* 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: 311 * 312 * interface [ -seed ] [ -phase number ] [ -net net-range ] 313 * [ -addr net.node ] [ -zone zonename ]... 314 * e.g. 315 * le0 -phase 1 -net 7938 -zone Argus 316 * or 317 * le0 -phase 2 -net 8043-8044 -zone Argus -zone "Research Systems" 318 * le0 -phase 1 -net 7938 -zone Argus 319 * 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 328 * interface. 329 */ 330int readconf(char *cf) 331{ 332 struct ifreq ifr; 333 struct interface *iface, *niface; 334 char line[ MAXLINELEN ], **argv, *p; 335 unsigned int i, j; 336 int s, cc = 0; 337 FILE *conf; 338 339 if ( cf == NULL ) { 340 p = _PATH_ATALKDCONF; 341 } else { 342 p = cf; 343 } 344 if (( conf = fopen( p, "r" )) == NULL ) { 345 return( -1 ); 346 } 347 348#ifndef __svr4__ 349 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) { 350 perror( "socket" ); 351 fclose(conf); 352 return -1; 353 } 354#endif /* __svr4__ */ 355 356 while ( fgets( line, sizeof( line ), conf ) != NULL ) { 357 if (( argv = parseline( line )) == NULL ) { 358 continue; 359 } 360 361#ifndef __svr4__ 362 /* 363 * Check that av[ 0 ] is a valid interface. 364 * Not possible under sysV. 365 */ 366 strlcpy( ifr.ifr_name, argv[ 0 ], sizeof(ifr.ifr_name) ); 367 368 /* for devices that don't support appletalk */ 369 if ((ioctl(s, SIOCGIFADDR, &ifr) < 0) && (errno == ENODEV)) { 370 perror(argv[0]); 371 goto read_conf_err; 372 } 373 374 if ( ioctl( s, SIOCGIFFLAGS, &ifr ) < 0 ) { 375 perror( argv[ 0 ] ); 376 goto read_conf_err; 377 } 378 379 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT |IFF_SLAVE)) { 380 fprintf( stderr, "%s: can't configure.\n", ifr.ifr_name ); 381 goto read_conf_err; 382 } 383 384#ifdef IFF_MULTICAST 385 if ((ifr.ifr_flags & IFF_MULTICAST) == 0) 386 fprintf(stderr, "%s: multicast may not work properly.\n", 387 ifr.ifr_name); 388#endif /* IFF_MULTICAST */ 389 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"); 394 goto read_conf_err; 395 } 396 397#endif /* __svr4__ */ 398 399 if (( niface = newiface( argv[ 0 ] )) == NULL ) { 400 perror( "newiface" ); 401 goto read_conf_err; 402 } 403 404 for ( i = 1; argv[ i ]; i += cc ) { 405 if ( argv[ i ][ 0 ] == '-' ) { 406 argv[ i ]++; 407 } 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 ] ); 412 if (cc < 0) 413 goto read_conf_err; 414 break; 415 } 416 } 417 } 418 if ( j >= sizeof( params ) / sizeof( params[ 0 ] )) { 419 fprintf( stderr, "%s: attribute not found.\n", argv[ i ] ); 420 goto read_conf_err; 421 } 422 } 423 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 )) { 429 break; 430 } 431 } 432 if ( iface ) { /* Already have this interface and phase */ 433 fprintf( stderr, "%s already configured!\n", niface->i_name ); 434 goto read_conf_err; 435 } 436 437#ifdef linux 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; 441 442 if ((niface->i_flags & IFACE_ALLMULTI) && !(niface->i_flags & IFACE_WASALLMULTI)) 443 ifsetallmulti(ifr.ifr_name, 1); 444#endif 445 446 if ( interfaces == NULL ) { 447 interfaces = niface; 448 } else { 449 for ( iface = interfaces; iface->i_next; iface = iface->i_next ) 450 ; 451 iface->i_next = niface; 452 } 453 niface->i_next = NULL; 454 } 455 456#ifndef __svr4__ 457 close( s ); 458#endif /* __svr4__ */ 459 460 fclose( conf ); 461 462 /* 463 * Note: we've added lo0 to the interface list previously, so we must 464 * have configured more than one interface... 465 */ 466 for ( iface = interfaces, cc = 0; iface; iface = iface->i_next, cc++ ) 467 ; 468 if ( cc >= IFBASE ) { 469 return( 0 ); 470 } else { 471 return( -1 ); 472 } 473 474read_conf_err: 475#ifndef __svr4__ 476 close(s); 477#endif /* __svr4__ */ 478 fclose(conf); 479 return -1; 480} 481 482int noallmulti( struct interface *iface, char **av _U_) 483{ 484 /* Linux specific, no effect on other platforms */ 485 iface->i_flags &= !IFACE_ALLMULTI; 486 487 return (1); 488} 489 490/*ARGSUSED*/ 491int router(struct interface *iface, char **av _U_) 492{ 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"); 496 return -1; 497 } 498 499 /* 500 * Check to be sure "-router" is before "-zone". 501 */ 502 if ( iface->i_czt ) { 503 fprintf( stderr, "Must specify -router before -zone.\n"); 504 return -1; 505 } 506 507 /* -router also implies -seed */ 508 iface->i_flags |= IFACE_RSEED | IFACE_SEED | IFACE_ISROUTER; 509 return( 1 ); 510} 511 512/*ARGSUSED*/ 513int dontroute(struct interface *iface, char **av _U_) 514{ 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"); 518 return -1; 519 } 520 521 iface->i_flags |= IFACE_DONTROUTE; 522 return( 1 ); 523} 524 525/*ARGSUSED*/ 526int seed( struct interface *iface, char **av _U_) 527{ 528 /* 529 * Check to be sure "-seed" is before "-zone". we keep the old 530 * semantics of just ignoring this in a routerless world. 531 */ 532 if ( iface->i_czt ) { 533 fprintf( stderr, "Must specify -seed before -zone(%s).\n", 534 iface->i_czt->zt_name); 535 return -1; 536 } 537 538 iface->i_flags |= IFACE_SEED; 539 return( 1 ); 540} 541 542int phase(struct interface *iface, char **av) 543{ 544 int n; 545 char *pnum; 546 547 if (( pnum = av[ 0 ] ) == NULL ) { 548 fprintf( stderr, "No phase.\n" ); 549 return -1; 550 } 551 552 switch ( n = atoi( pnum )) { 553 case 1 : 554 iface->i_flags |= IFACE_PHASE1; 555 break; 556 557 case 2 : 558 iface->i_flags |= IFACE_PHASE2; 559 break; 560 561 default : 562 fprintf( stderr, "No phase %d.\n", n ); 563 return -1; 564 } 565 return( 2 ); 566} 567 568int net(struct interface *iface, char **av) 569{ 570 char *nrange; 571 char *stop; 572 int net; 573 574 if (( nrange = av[ 0 ] ) == NULL ) { 575 fprintf( stderr, "No network.\n" ); 576 return -1; 577 } 578 579 if (( stop = strchr( nrange, '-' )) != NULL ) { 580 stop++; 581 } 582 net = atoi( nrange ); 583 if ( net < 0 || net >= 0xffff ) { 584 fprintf( stderr, "Bad network: %d\n", net ); 585 return -1; 586 } 587 588 if ( iface->i_rt == NULL && ( iface->i_rt = newrt(iface)) == NULL ) { 589 perror( "newrt" ); 590 return -1; 591 } 592 593 if ( iface->i_flags & IFACE_PHASE1 ) { 594 if ( stop != NULL ) { 595 fprintf( stderr, "Phase 1 doesn't use an address range.\n" ); 596 return -1; 597 } 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 )); 602 return -1; 603 } 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 ) { 608 net = atoi( stop ); 609 if ( net < 0 || net >= 0xffff ) { 610 fprintf( stderr, "Bad network: %d\n", net ); 611 return -1; 612 } 613 } 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 )); 624 return -1; 625 } 626 if ( iface->i_rt->rt_firstnet != iface->i_rt->rt_lastnet ) { 627 iface->i_rt->rt_flags |= RTMPTAB_EXTENDED; 628 } 629 } else { 630 fprintf( stderr, "Must specify phase before networks.\n" ); 631 return -1; 632 } 633 return( 2 ); 634} 635 636int addr(struct interface *iface, char **av) 637{ 638 if ( av[ 0 ] == NULL ) { 639 fprintf( stderr, "No address.\n" ); 640 return -1; 641 } 642 if ( atalk_aton( av[ 0 ], &iface->i_caddr.sat_addr ) == 0 ) { 643 fprintf( stderr, "Bad address, %s\n", av[ 0 ] ); 644 return -1; 645 } 646 647 if ( iface->i_rt ) { 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 )); 656 return -1; 657 } 658 } else { 659 if (( iface->i_rt = newrt(iface)) == NULL ) { 660 perror( "newrt" ); 661 return -1; 662 } 663 iface->i_rt->rt_firstnet = iface->i_rt->rt_lastnet = 664 iface->i_caddr.sat_addr.s_net; 665 } 666 667 return( 2 ); 668} 669 670int zone(struct interface *iface, char **av) 671{ 672 struct ziptab *zt; 673 char *zname; 674 675 if ( av[ 0 ] == NULL ) { 676 fprintf( stderr, "No zone.\n" ); 677 return -1; 678 } 679 680 /* codepage conversion */ 681 if ((size_t)(-1) == convert_string_allocate(CH_UNIX, CH_MAC, av[0], -1, &zname)) { 682 zname = strdup(av[0]); 683 } 684 685 /* 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. 689 */ 690 if ( iface->i_flags & IFACE_SEED ) { 691 if ( iface->i_rt == NULL ) { 692 fprintf( stderr, "Must specify net-range before zones.\n" ); 693 return -1; 694 } 695 696 if (( zt = newzt( strlen( zname ), zname )) == NULL ) { 697 perror( "newzt" ); 698 return -1; 699 } 700 if ( iface->i_czt == NULL ) { 701 iface->i_czt = zt; 702 } else { 703 zt->zt_next = iface->i_czt->zt_next; 704 iface->i_czt->zt_next = zt; 705 } 706 } 707 free(zname); 708 709 return( 2 ); 710} 711 712/* 713 * Get the configuration from the kernel. Only called if there's no 714 * configuration. 715 */ 716int getifconf(void) 717{ 718 struct interface *iface, *niface; 719 struct ifreq ifr; 720 char **start, **list; 721 int s; 722 723 if (( s = socket( AF_APPLETALK, SOCK_DGRAM, 0 )) < 0 ) { 724 perror( "socket" ); 725 return -1; 726 } 727 728 start = list = getifacelist(); 729 while (list && *list) { 730 strlcpy(ifr.ifr_name, *list, sizeof(ifr.ifr_name)); 731 list++; 732 733 if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) 734 continue; 735 736 if (ifr.ifr_flags & (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_SLAVE)) 737 continue; 738 739 if ((ifr.ifr_flags & IFF_UP) == 0) 740 continue; 741 742 /* for devices that don't support appletalk */ 743 if (ioctl(s, SIOCGIFADDR, &ifr) < 0 && (errno == ENODEV)) 744 continue; 745 746 for ( iface = interfaces; iface; iface = iface->i_next ) { 747 if ( strcmp( iface->i_name, ifr.ifr_name ) == 0 ) { 748 break; 749 } 750 } 751 if ( iface ) { /* Already have this interface name */ 752 continue; 753 } 754 755 756#ifdef IFF_MULTICAST 757 if ((ifr.ifr_flags & IFF_MULTICAST) == 0) 758 fprintf(stderr, "%s: multicast may not work correctly.\n", 759 ifr.ifr_name); 760#endif /* IFF_MULTICAST */ 761 762 if (addmulti(ifr.ifr_name, NULL) < 0) { 763 fprintf(stderr, "%s: disabled.\n", ifr.ifr_name); 764 continue; 765 } 766 767 if (( niface = newiface( ifr.ifr_name )) == NULL ) { 768 perror( "newiface" ); 769 close(s); 770 freeifacelist(start); 771 return -1; 772 } 773 /* 774 * Could try to get the address from the kernel... 775 */ 776 777 if ( interfaces == NULL ) { 778 interfaces = niface; 779 } else { 780 for ( iface = interfaces; iface->i_next; iface = iface->i_next ) 781 ; 782 iface->i_next = niface; 783 } 784 niface->i_next = NULL; 785 } 786 freeifacelist(start); 787 (void)close( s ); 788 return( 0 ); 789} 790 791/* 792 * Allocate a new interface structure. Centralized here so we can change 793 * the interface structure and have it updated nicely. 794 */ 795 796struct interface *newiface( const char *name) 797{ 798 struct interface *niface; 799 800 if (( niface = (struct interface *)calloc(1, sizeof( struct interface ))) 801 == NULL ) { 802 return( NULL ); 803 } 804 strlcpy( niface->i_name, name, sizeof(niface->i_name)); 805#ifdef BSD4_4 806 niface->i_addr.sat_len = sizeof( struct sockaddr_at ); 807#endif /* BSD4_4 */ 808 niface->i_addr.sat_family = AF_APPLETALK; 809#ifdef BSD4_4 810 niface->i_caddr.sat_len = sizeof( struct sockaddr_at ); 811#endif /* BSD4_4 */ 812 niface->i_caddr.sat_family = AF_APPLETALK; 813#ifdef linux 814 niface->i_flags = IFACE_ALLMULTI; 815#endif 816 return( niface ); 817} 818 819#ifdef __svr4__ 820int plumb(void) 821{ 822 struct interface *iface; 823 char device[ MAXPATHLEN + 1], *p, *t; 824 int fd, ppa; 825 int digits = 0; 826 827 for ( iface = interfaces; iface != NULL; iface = iface->i_next ) { 828 if ( strcmp( iface->i_name, LOOPIFACE ) == 0 ) { 829 continue; 830 } 831 832 strcpy( device, "/dev/" ); 833 strcat( device, iface->i_name ); 834 for (t = device; *t != '\0' ; ++t) { 835 if (isdigit(*t) == 0) { 836 p = t + 1; 837 } 838 else { 839 digits++; 840 } 841 } 842 843 if (digits == 0) { 844 LOG(log_error, logtype_atalkd, "plumb: invalid device: %s", device ); 845 return -1; 846 } 847 ppa = atoi( p ); 848 *p = '\0'; 849 850 if (( fd = open( device, O_RDWR, 0 )) < 0 ) { 851 LOG(log_error, logtype_atalkd, "%s: %s", device, strerror(errno) ); 852 return -1; 853 } 854 if ( ioctl( fd, I_PUSH, "ddp" ) < 0 ) { 855 LOG(log_error, logtype_atalkd, "I_PUSH: %s", strerror(errno) ); 856 close(fd); 857 return -1; 858 } 859 if ( ioctl( fd, IF_UNITSEL, ppa ) < 0 ) { 860 LOG(log_error, logtype_atalkd, "IF_UNITSEL: %s", strerror(errno) ); 861 close(fd); 862 return -1; 863 } 864 865 /* configure multicast. */ 866 if (addmulti(iface->i_name, NULL) < 0) { 867 perror(iface->i_name); 868 fprintf(stderr,"Can't configure multicast.\n"); 869 close(fd); 870 return -1; 871 } 872 873 LOG(log_info, logtype_atalkd, "plumbed %s%d", device, ppa ); 874 } 875 876 return( 0 ); 877} 878#endif /* __svr4__ */ 879