/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 *	Copyright (c) 1988, 1989, 1998 Apple Computer, Inc. 
 *
 *	The information contained herein is subject to change without
 *	notice and  should not be  construed as a commitment by Apple
 *	Computer, Inc. Apple Computer, Inc. assumes no responsibility
 *	for any errors that may appear.
 *
 *	Confidential and Proprietary to Apple Computer, Inc.
 */

/* "@(#)zip_lolist.c: 2.0, 1.12; 2/10/93; Copyright 1988-89, Apple Computer, Inc." */

/*
 * Title:	zip_locallist.c
 *
 * Facility:	AppleTalk Zone Information Protocol Library Interface
 *
 * History:
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <mach/boolean.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <net/if.h>

#include <netat/appletalk.h>
#include <netat/ddp.h>
#include <netat/atp.h>
#include <netat/zip.h>
#include <netat/at_var.h>

#include "at_proto.h"

#define	SET_ERRNO(e) errno = e

#define TOTAL_ALLOWED ATP_DATA_SIZE-sizeof(at_nvestr_t)

extern int zip_getzonesfrombridge(char *ifName, int *context, 
				  u_char *zones, int size, int local);


/* in_list() returns 1 if ifName is on interface list nameList,
   and 0, if it's not.  in_list() returns 0 if IfName is NULL or empty.
*/

int in_list(ifName, nameList)
     char *ifName;
     at_ifnames_t *nameList;
{
	int ifno;

	if (!ifName || !ifName[0])
	    return(0);

	/* find matching ifno */
	for (ifno=0; ifno < IF_TOTAL_MAX; ifno++) {
	     if (!strcmp(ifName, (char *)nameList->at_if[ifno])) {
		return(1);
	     }
	}
	return(0);
}

/* zip_getlocalzones() will return the zone count on success, 
   and -1 on failure. */

int zip_getlocalzones(
	char *ifName,
		/* If ifName is a null pointer (ZIP_DEF_INTERFACE) the default
		   interface will be used.
		*/
	int *context,
		/* *context should be set to ZIP_FIRST_ZONE for the first call.
		   The returned value may be used in the next call, unless it
		   is equal to ZIP_NO_MORE_ZONES.
		*/
	u_char *zones,
		/* Pointer to the beginning of the "zones" buffer.
		   Zone data returned will be a sequence of at_nvestr_t
		   Pascal-style strings, as it comes back from the 
		   ZIP_GETLOCALZONES request sent over ATP 
		*/
	int size
		/* Length of the "zones" buffer; must be at least 
		   (ATP_DATA_SIZE+1) bytes in length.
		*/
)
{
	int start = *context;
	int if_id;
	at_state_t      global_state;
	at_nvestr_t	*pz;
	int total=0, i, skipped = 0;
	zone_usage_t	ifz;

	if (start < ZIP_FIRST_ZONE) {
		return(-1);
	}
	if (0 > (if_id = socket(AF_APPLETALK, SOCK_RAW, 0)))
		return(-1);

	if (ioctl(if_id, AIOCGETSTATE, (caddr_t)&global_state)) {
		fprintf(stderr,"error getting Appletalk mode\n");
		(void)close (if_id);
		return(-1);
	}
	if (!(global_state.flags & AT_ST_ROUTER) &&
	    !(global_state.flags & AT_ST_MULTIHOME)) {
		(void)close (if_id);
		return(zip_getzonesfrombridge(ifName, context, zones, 
					      size, TRUE));
	} else { /* multihome or router mode */

		pz = (at_nvestr_t *)zones;
		ifz.zone_index = i = start-1;
		total=0;
		for ( ; total < TOTAL_ALLOWED; ifz.zone_index = ++i) {
			if (ioctl(if_id, AIOCGETZNUSAGE, (caddr_t)&ifz))
			    if (errno != ENOENT) {
				fprintf(stderr,"error getting Appletalk local zones\n");
				(void)close (if_id);
				return(-1);
			    } else {
				*context = ZIP_NO_MORE_ZONES;
				(void)close (if_id);
				return(i-start+1-skipped);
			    }
			/* if we're looking for a certain interface */
			if (ifName && strlen(ifName)) {
				/* if it's not for this interface, get the 
				   next local zone */
				if (!in_list(ifName, &ifz.zone_iflist)) {
					skipped++;
				  	continue;
				}
			}
			*pz = ifz.zone_name; 
			total += (pz->len + 1);
			pz = (at_nvestr_t*)((caddr_t)pz + pz->len +1);
		}
		*context = i+2;
		(void)close (if_id);
		return(i-start+2-skipped);
	}
	(void)close (if_id);
	return(-1);
}
