/*
 * (llc_glob.c)
 *
 * Copyright (c) 1997 by Procom Technology,Inc.
 *
 * This program can be redistributed or modified under the terms of the 
 * GNU General Public License as published by the Free Software Foundation.
 * This program is distributed without any warranty or implied warranty
 * of merchantability or fitness for a particular purpose.
 *
 * See the GNU General Public License for more details.
 *
 */
 

#define LLC_GLOB_C

#include <linux/config.h>
#include <linux/netdevice.h>
#include <linux/net_alias.h>
#include <net/cm_types.h>
#include <net/llc_if.h>
#include <net/stk_rsrc.h>
#include <net/llc_glob.h>
#include <net/llc_dbg.h>

#ifdef LLC_GLOB_DBG
  #define  DBG_MSG(body) { printk body; }
#else
  #define  DBG_MSG(body)  ;
#endif

/* defined constants */


/* data structures */

typedef struct dev_cache
{
	struct device *	dev;
	us16		addr_len;
	us8		addr[MAX_ADDR_LEN];
} dev_cache_t;


typedef struct
{  
	us32		max_nbr_saps;
	us32		max_nbr_connections;
	us32		max_pdu_octets;
	us32		min_pdu_octets;
	dev_cache_t *	device_cache;
	us32		device_cache_size;
} global_parameters_t;


static us32			Module_init = NO;

static global_parameters_t	Backup_global_parameters;
static global_parameters_t	Real_global_parameters;


static void build_device_cache (void);


/*
 * Function: llc_glob_init
 *
 * Parameters:
 *  None
 *
 * Returns:
 *  None
 */

us16
llc_glob_init (void)
{
	if (Module_init == YES) {
		return (0);
	}
	Backup_global_parameters.max_nbr_saps = LLC_GLOBAL_DEFAULT_MAX_NBR_SAPS;
	Backup_global_parameters.max_nbr_connections =
					LLC_GLOBAL_DEFAULT_MAX_NBR_CONNECTIONS;
	Backup_global_parameters.max_pdu_octets =
					LLC_GLOBAL_DEFAULT_MAX_PDU_OCTETS;
	Backup_global_parameters.min_pdu_octets =
					LLC_GLOBAL_DEFAULT_MIN_PDU_OCTETS;
	build_device_cache ();
	memcpy (&Real_global_parameters, &Backup_global_parameters, 
					sizeof (global_parameters_t));
	Module_init = YES;
	return (0);
}


/*
 * Function: llc_glob_exit
 *
 * Parameters:
 *  None
 *
 * Returns:
 *  0
 */

us16
llc_glob_exit (void)
{
	if (Module_init == NO) {
		return (0);
	}
	Module_init = NO;
	return (0);
}

/*
 * Function: access_max_nbr_saps
 * 
 * Description: 
 *  Sets/Extracts the maximum number of saps to/from the
 *  Real_global_parameters
 *
 * Parameters:
 *  action : The action to perform (Extract or Set)
 *  value : Address of the value to set or be set
 *
 * Returns:
 *  0 : If action is valid
 *  1 : Otherwise
 */

us16
access_max_nbr_saps (us8 action, us32 * value)
{
	us16	rc = 1;

	if (Module_init == NO) {
		return (1);
	}
	switch (action) {
		case ACTION_SET:
			rc = 0;
			Real_global_parameters.max_nbr_saps = (us32) *value;
			break;
		case ACTION_GET:
			*value = (us32) Real_global_parameters.max_nbr_saps;
			rc = 0;
			break;
	}
	return (rc);
}

/*
 * Function: access_max_nbr_connections
 * 
 * Description: 
 *  Sets/Extracts the maximum number of connections to/from the
 *  Real_global_parameters
 *
 * Parameters:
 *  action : The action to perform (Extract or Set)
 *  value : Address of the value to set or be set
 *
 * Returns:
 *  0 : If action is valid
 *  1 : Otherwise
 */

us16
access_max_nbr_connections (us8 action, us32 * value)
{
	us16	rc = 1;

	if (Module_init == NO) {
		return (1);
	}
	switch (action) {
		case ACTION_SET:
			rc = 0;
			Real_global_parameters.max_nbr_connections =
						(us32) *value;
			break;
		case ACTION_GET:
			*value = (us32) Real_global_parameters.max_nbr_connections;
			rc = 0;
			break;
	}
	return (rc);
}

/*
 * Function: access_max_pdu_octets
 * 
 * Description: 
 *  Sets/Extracts the maximum number of bytes in a PDU to/from the
 *  Real_global_parameters
 *
 * Parameters:
 *  action : The action to perform (Extract or Set)
 *  value : Address of the value to set or be set
 *
 * Returns:
 *  0 : If action is valid
 *  1 : Otherwise
 */

us16
access_max_pdu_octets (us8 action, us32 * value)
{
	us16	rc = 1;

	if (Module_init == NO) {
		return (1);
	}
	switch (action) {
		case ACTION_SET:
			rc = 0;
			Real_global_parameters.max_pdu_octets = (us32) *value;
			break;
		case ACTION_GET:
			*value = (us32) Real_global_parameters.max_pdu_octets;
			rc = 0;
			break;
	}
	return (rc);
}

/*
 * Function: access_min_pdu_octets
 * 
 * Description:
 *  Sets/Extracts the minimum number of bytes in a PDU to/from the
 *  Real_global_parameters
 *
 * Parameters:
 *  action : The action to perform (Extract or Set)
 *  value : Address of the value to set or be set
 *
 * Returns:
 *  0 : If action is valid
 *  1 : Otherwise
 */

us16
access_min_pdu_octets (us8 action, us32 * value)
{
	us16	rc = 1;

	if (Module_init == NO) {
		return (1);
	}
	switch (action) {
		case ACTION_SET:
			rc = 0;
			Real_global_parameters.min_pdu_octets = (us32) *value;
			break;
		case ACTION_GET:
			*value = (us32) Real_global_parameters.min_pdu_octets;
			rc = 0;
			break;
	}
	return (rc);
}

/*
 * Function: access_device_mac_addr
 * 
 * Description:
 *  Sets/Extracts the minimum number of bytes in a PDU to/from the
 *  Real_global_parameters
 *
 * Parameters:
 *  action : The action to perform (Extract or Set)
 *  dev : 
 *  mac_addr :
 *
 * Returns:
 *  0 : If action is valid
 *  1 : Otherwise
 */

us16 access_device_mac_addr (us8 action, struct device * dev, us8 * mac_addr)
{
	us16	i;
	us16	rc = 1;

	switch (action) {
		case ACTION_SET:
			break;
		case ACTION_GET:
			for (i = 0; (i < Real_global_parameters.device_cache_size)
							&& rc; i++) {
				if (Real_global_parameters.device_cache[i].dev == dev) {
					memcpy (mac_addr, 
						Real_global_parameters.device_cache[i].addr, 6);
					rc = 0;
				}
			}
			break;
	}
	return (rc);
}


/*
 * Function: access_all_devices
 *
 * Parameters:
 *
 * Returns:
 *
 */

us16
access_all_devices (us8 action, void ** dev, us32 * nbr_devs)
{
	us16	i;
	us16	rc = 1;

	dev[0] = dev_base->next;
	*nbr_devs = Real_global_parameters.device_cache_size;
	return 0;
	switch (action) {
		case ACTION_SET:
			break;
		case ACTION_GET:
			for (i = 0; (i < Real_global_parameters.device_cache_size)
								&& rc; i++) {
				dev[i] = Real_global_parameters.device_cache[i].dev;
			}
			rc = 0;
			*nbr_devs = Real_global_parameters.device_cache_size;
			break;
	}
	return (rc);
}

/*
 * Function: device_getallbytype
 *
 * Parameters:
 *
 * Returns:
 *
 */

int
device_getallbytype (const char *abbrev_name, char ** full_name)
{
	struct device *	dev;
	int		nbr = 0;

	for (dev = dev_base; dev != NULL; dev = dev->next) {
		if (!strncmp (dev->name, abbrev_name, strlen (abbrev_name))) {
			strcpy (full_name[nbr++], dev->name);
		}
	}
	return (nbr);
}

/*
 * Function: build_device_cache
 *
 * Parameters:
 *
 * Returns:
 *  None
 */

static void
build_device_cache ()
{
	char *	tmp;
	char *	net_device_names[11];
	us16	i;
	us16	cache_entries;
	us16	eth_devs;
	us16	tr_devs;
	struct device *	this_dev;
	dev_cache_t *	device_cache;

	tmp = (char *) kmalloc (110, GFP_KERNEL);
	if (tmp) {
		for (i = 0; i < 11; i++, tmp += 10) {
			net_device_names [i] = tmp;
		}
	} else{
		#ifdef FDBG
		printk(KERN_ERR "\nbuild_device_cache : failed,can't allocate memory\n");
		#endif
	}
	eth_devs = device_getallbytype ("eth", net_device_names);
	tr_devs = device_getallbytype ("tr", &net_device_names[eth_devs]);
	cache_entries = eth_devs + tr_devs;
	device_cache = (dev_cache_t *) kmalloc ((sizeof(dev_cache_t) *
					cache_entries), GFP_KERNEL);
	if (device_cache) {
		for (i = 0; i < cache_entries; i++) {       
			for (i = 0; i < cache_entries; i++) {
				this_dev = dev_get (net_device_names [i]);
				#ifdef LLC_GLOB_DBG
				printk(KERN_ERR "device name : %s,this_dev->name : %s",
					net_device_names[0],this_dev->name);
				#endif
				#ifdef CONFIG_NET_ALIAS
				if (net_alias_is (this_dev)) {
					this_dev = net_alias_main_dev (this_dev);
				}
				#endif
				device_cache[i].dev = this_dev;
				memcpy (device_cache[i].addr, this_dev->dev_addr,
						this_dev->addr_len);
				device_cache[i].addr_len = this_dev->addr_len;
			}
		}
		Backup_global_parameters.device_cache = device_cache;
		Backup_global_parameters.device_cache_size = cache_entries;
	} else{
		#ifdef FDBG
		printk(KERN_ERR "\nbuild_device_cache : failed,can't allocate memory for device cache\n");
		#endif
	} 
	return;
}
