/* 
   This file contains wireless extension handlers.

   This is part of rtl8180 OpenSource driver.
   Copyright (C) Andrea Merello 2004-2005  <andreamrl@tiscali.it> 
   Released under the terms of GPL (General Public Licence)
   
   Parts of this driver are based on the GPL part 
   of the official realtek driver.
   
   Parts of this driver are based on the rtl8180 driver skeleton 
   from Patric Schenke & Andres Salomon.

   Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
   
   We want to tanks the Authors of those projects and the Ndiswrapper 
   project Authors.
*/



#include "r8180.h"
#include "r8180_hw.h"
#include "r8180_sa2400.h"

#define RATE_COUNT 4
u32 rtl8180_rates[] = {1000000,2000000,5500000,11000000};

static int r8180_wx_get_freq(struct net_device *dev,
			     struct iw_request_info *a,
			     union iwreq_data *wrqu, char *b)
{
	struct r8180_priv *priv = dev->priv;
	struct iw_freq *fwrq = & wrqu->freq;

#ifdef WEXT_USECHANNELS
	fwrq->m = priv->chan;
	fwrq->e = 0;
#else
	fwrq->m = wlan_frequencies[priv->chan-1] * 100000;
	fwrq->e = 1;
#endif
	return 0;
}


int r8180_wx_set_key(struct net_device *dev, struct iw_request_info *info, 
		     union iwreq_data *wrqu, char *key)
{
	struct r8180_priv *priv = dev->priv;
	struct iw_point *erq = &(wrqu->encoding);	

	if (erq->flags & IW_ENCODE_DISABLED) {
	}
	
	
/*	i = erq->flags & IW_ENCODE_INDEX;
	if (i < 1 || i > 4)
*/	
	
	if (erq->length > 0) {

		//int len = erq->length <= 5 ? 5 : 13;
		
		u32* tkey= (u32*) key;
		priv->key0[0] = tkey[0];
		priv->key0[1] = tkey[1];
		priv->key0[2] = tkey[2];
		priv->key0[3] = tkey[3] &0xff;
		DMESG("Setting wep key to %x %x %x %x", 
		      tkey[0],tkey[1],tkey[2],tkey[3]);
		rtl8180_set_hw_wep(dev);
	}
	return 0;
}


static int r8180_set_beaconinterval(struct net_device *dev, struct iw_request_info *aa,
			  union iwreq_data *wrqu, char *b)
{
	int *parms = (int *)b;
	int bi = parms[0];
	
	struct r8180_priv *priv = dev->priv;
	
	down(&priv->wx_sem);
	DMESG("setting beacon interval to %x",bi);
	
	priv->ieee80211->beacon_interval=bi;
	rtl8180_commit(dev);
	up(&priv->wx_sem);
		
	return 0;	
}


static int r8180_debug_tx(struct net_device *dev, struct iw_request_info *aa,
			  union iwreq_data *wrqu, char *b)
{struct r8180_priv *priv=dev->priv;	

	write_nic_byte(dev,TX_DMA_POLLING,
		       (1<<TX_DMA_POLLING_NORMPRIORITY_SHIFT) |
		        priv->dma_poll_mask);	
/*
	if (!priv->up) return -1;

	int *parms = (int *)b;
	int len = parms[0];
	char probe[] = {0x40,0x00,0x00,0xff,0xff,0xff,0xff,
			0xff,0xff,0xff,0xff,0xff,0xff};

	char *a = (char *) kmalloc(len*sizeof(char)+sizeof(probe), GFP_KERNEL);
	int i,j;
	
	
	for(i=0;i<sizeof(probe);i++)
		a[i]=probe[i];

	for(j=0;j<len-1;i++,j++){
		if (i%2) 
			a[i]=0xab;
		else 
			a[i]=0xcd;
	}
	
	a[i]=0x24;
	
	DMESG("TX %x bytes..", len+sizeof(probe));
	rtl8180_tx(dev, (u32*)a, i+1, NORM_PRIORITY, 0, 0);
	kfree(a);
	
	*/
	#if 0
	struct r8180_priv *priv = dev->priv;
	fix_tx_fifo(dev);
	#endif
	//check_txnpbuf(dev);
	return 0;
}


static int r8180_wx_get_mode(struct net_device *dev, struct iw_request_info *a,
			     union iwreq_data *wrqu, char *b)
{
	struct r8180_priv *priv=dev->priv;	

	wrqu->mode = priv->ieee80211->iw_mode;
	return 0;
}



static int r8180_wx_get_rate(struct net_device *dev, 
			     struct iw_request_info *info, 
			     union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;
	return ieee80211_r8180_wx_get_rate(priv->ieee80211,info,wrqu,extra);
}



static int r8180_wx_set_rate(struct net_device *dev, 
			     struct iw_request_info *info, 
			     union iwreq_data *wrqu, char *extra)
{
	int ret;
	struct r8180_priv *priv = dev->priv;	
	
	down(&priv->wx_sem);

	ret = ieee80211_r8180_wx_set_rate(priv->ieee80211,info,wrqu,extra);
	
	up(&priv->wx_sem);
	
	return ret;
}


static int r8180_wx_set_crcmon(struct net_device *dev, 
			       struct iw_request_info *info, 
			       union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;
	int *parms = (int *)extra;
	int enable = (parms[0] > 0);
	short prev = priv->crcmon;

	down(&priv->wx_sem);
	
	if(enable) 
		priv->crcmon=1;
	else 
		priv->crcmon=0;

	DMESG("bad CRC in monitor mode are %s", 
	      priv->crcmon ? "accepted" : "rejected");

	if(prev != priv->crcmon && priv->up){
		rtl8180_down(dev);
		rtl8180_up(dev);
	}
	
	up(&priv->wx_sem);
	
	return 0;
}


static int r8180_wx_set_monitor(struct net_device *dev, 
				struct iw_request_info *info, 
				union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;
	int *parms = (int *)extra;
	int enable = (parms[0] > 0);
	
	down(&priv->wx_sem);
	
	if (enable && IW_MODE_MONITOR == priv->ieee80211->iw_mode) {
		priv->rf_set_chan(dev, parms[1]);
		goto out;
	}
	
	
	if(enable) {
	  		priv->chan=parms[1];
			priv->rf_set_chan(dev, parms[1]);
			priv->ieee80211->iw_mode = IW_MODE_MONITOR;
			/* this is the priv for orinoco kismet compatibility, so
			   uses the normal ieee80211 header, regardless the prism
			   header flag
			 */
			dev->type=ARPHRD_IEEE80211;
	  			
				
	} else {
		
		if (priv->ieee80211->iw_mode != IW_MODE_MONITOR)
			goto out;
		
		priv->ieee80211->iw_mode = IW_MODE_INFRA;
		dev->type=ARPHRD_ETHER;
	}

	if(priv->up){
		rtl8180_down(dev);
		rtl8180_up(dev);
	}
	
out:
	up(&priv->wx_sem);
	return 0;
}


static int r8180_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
			     union iwreq_data *wrqu, char *b)
{
	struct r8180_priv *priv = dev->priv;
	
	down(&priv->wx_sem);
	
	if (wrqu->mode == priv->ieee80211->iw_mode)
		goto out;
		
	if(wrqu->mode == IW_MODE_MONITOR){
		if(priv->prism_hdr)
			dev->type=ARPHRD_IEEE80211_PRISM;
		else  
			dev->type=ARPHRD_IEEE80211;
	}else{
		dev->type=ARPHRD_ETHER;
	}
	
	priv->ieee80211->iw_mode = wrqu->mode;
	
	if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
		IBSS_randomize_cell(dev);
	if(priv->ieee80211->iw_mode == IW_MODE_MASTER)
		memcpy(priv->ieee80211->beacon_cell_ssid, dev->dev_addr, ETH_ALEN);
	
	/* if the user set the MAC of the ad-hoc cell and then
	 * switch to managed mode, we have to make sure that association
	 * attempts does not fail just because the user provide the essid
	 * and the nic is still checking for the AP MAC
	 */
	if(priv->ieee80211->iw_mode == IW_MODE_INFRA)
		memset(priv->ieee80211->ap, 0, ETH_ALEN); 
	
	if(priv->up) {
		rtl8180_down(dev);
		rtl8180_up(dev);
	}
	
out:
	up(&priv->wx_sem);
	return 0;
}


static int rtl8180_wx_get_range(struct net_device *dev, 
				struct iw_request_info *info, 
				union iwreq_data *wrqu, char *extra)
{
	struct iw_range *range = (struct iw_range *)extra;
	struct r8180_priv *priv = dev->priv;
	u16 val;
	int i;

	wrqu->data.length = sizeof(*range);
	memset(range, 0, sizeof(*range));

	/* Let's try to keep this struct in the same order as in
	 * linux/include/wireless.h
	 */
	
	/* TODO: See what values we can set, and remove the ones we can't
	 * set, or fill them with some default data.
	 */

	/* ~5 Mb/s real (802.11b) */
	range->throughput = 5 * 1000 * 1000;     

	// TODO: Not used in 802.11b?
//	range->min_nwid;	/* Minimal NWID we are able to set */
	// TODO: Not used in 802.11b?
//	range->max_nwid;	/* Maximal NWID we are able to set */
	
        /* Old Frequency (backward compat - moved lower ) */
//	range->old_num_channels; 
//	range->old_num_frequency;
//	range->old_freq[6]; /* Filler to keep "version" at the same offset */

//	range->sensitivity;	/* signal level threshold range */
	
	range->max_qual.qual = 100;
	/* TODO: Find real max RSSI and stick here */
	range->max_qual.level = 0;
	range->max_qual.noise = -98;
	range->max_qual.updated = 7; /* Updated all three */

	range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
	/* TODO: Find real 'good' to 'bad' threshol value for RSSI */
	range->avg_qual.level = 20 + -98;
	range->avg_qual.noise = 0;
	range->avg_qual.updated = 7; /* Updated all three */

	range->num_bitrates = RATE_COUNT;
	
	for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
		range->bitrate[i] = rtl8180_rates[i];
	}
	
	range->min_frag = MIN_FRAG_THRESHOLD;
	range->max_frag = MAX_FRAG_THRESHOLD;
	
	range->pm_capa = 0;

	range->we_version_compiled = WIRELESS_EXT;
	range->we_version_source = 16;

//	range->retry_capa;	/* What retry options are supported */
//	range->retry_flags;	/* How to decode max/min retry limit */
//	range->r_time_flags;	/* How to decode max/min retry life */
//	range->min_retry;	/* Minimal number of retries */
//	range->max_retry;	/* Maximal number of retries */
//	range->min_r_time;	/* Minimal retry lifetime */
//	range->max_r_time;	/* Maximal retry lifetime */

        range->num_channels = 14;

	for (i = 0, val = 0; i < 14; i++) {
		
		// Include only legal frequencies for some countries
		if ((priv->challow)[i+1]) {
		        range->freq[val].i = i + 1;
			range->freq[val].m = wlan_frequencies[i] * 100000;
			range->freq[val].e = 1;
			val++;
		} else {
			// FIXME: do we need to set anything for channels
			// we don't use ?
		}
		
		if (val == IW_MAX_FREQUENCIES)
		break;
	}

	range->num_frequency = val;
	return 0;
}


static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
			     union iwreq_data *wrqu, char *b)
{
	struct r8180_priv *priv = dev->priv;

#if 0
	/* this code was for sync scanning */
	int i;
	
	for(i=1; i<=14; i++){
		rf_set_chan(dev,i);
		mdelay(500);
	}
#endif
	if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || !priv->up) return -1;
	return 0;
}


static int r8180_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
			     union iwreq_data *wrqu, char *b)
{

	int ret;
	struct r8180_priv *priv = dev->priv;
	
	down(&priv->wx_sem);
	
	ret =-1;
	
	if(priv->ieee80211->iw_mode == IW_MODE_MONITOR || !priv->up) 
		goto out;

	ret = ieee80211_r8180_wx_get_scan(priv->ieee80211, a, wrqu, b);
out:
	up(&priv->wx_sem);
	return ret;
}


static int r8180_wx_set_essid(struct net_device *dev, 
			      struct iw_request_info *a,
			      union iwreq_data *wrqu, char *b)
{
	struct r8180_priv *priv = dev->priv;
	
	int ret;
	
	down(&priv->wx_sem);
	
	if(wrqu->essid.length > SSID_LENGTH + 1){
		ret= -E2BIG;
		goto out;
	}
	
	if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){
		ret= -1;
		goto out;
	}
	
	if(priv->ieee80211->iw_mode == IW_MODE_INFRA){
		rtl8180_disassociate(dev);
		rtl8180_start_scanning(dev);
	}
	
	ret =  ieee80211_r8180_wx_set_essid(priv->ieee80211,a,wrqu,b);
	
	if(ret) goto out;
	
	if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
		IBSS_randomize_cell(dev);
	
	if(priv->ieee80211->iw_mode == IW_MODE_ADHOC ||
		priv->ieee80211->iw_mode == IW_MODE_MASTER )
	
	rtl8180_commit(dev);
out:
	up(&priv->wx_sem);
	return ret;
}


static int r8180_wx_get_essid(struct net_device *dev, 
			      struct iw_request_info *a,
			      union iwreq_data *wrqu, char *b)
{
	int ret;
	struct r8180_priv *priv = dev->priv;
	
	down(&priv->wx_sem);
	
	ret = ieee80211_r8180_wx_get_essid(priv->ieee80211, a, wrqu, b);

	up(&priv->wx_sem);
	
	return ret;
}


static int r8180_wx_set_freq(struct net_device *dev, struct iw_request_info *a,
			     union iwreq_data *wrqu, char *b)
{
	int ret;
	struct r8180_priv *priv = dev->priv;
	struct iw_freq *fwrq = & wrqu->freq;

	down(&priv->wx_sem);
	
	if(priv->ieee80211->iw_mode == IW_MODE_INFRA){ 
		ret = -1;
		goto out;
	}

	/* if setting by freq convert to channel */
	if (fwrq->e == 1) {
		if ((fwrq->m >= (int) 2.412e8 &&
		     fwrq->m <= (int) 2.487e8)) {
			int f = fwrq->m / 100000;
			int c = 0;
			
			while ((c < 14) && (f != wlan_frequencies[c]))
				c++;
			
			/* hack to fall through */
			fwrq->e = 0;
			fwrq->m = c + 1;
		}
	}
	
	if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1 ){ 
		ret = -EOPNOTSUPP;
		goto out;
	
	}else { /* Set the channel */
		
		//	DMESG("setting ch %d",fwrq->m);
		rtl8180_rtx_disable(dev);

		priv->chan=fwrq->m;
		rtl8180_set_chan(dev, fwrq->m);
		
		if(priv->up){
			// fix_rx_fifo(dev); // already done in rx_enable
			rtl8180_rx_enable(dev);
			rtl8180_tx_enable(dev);
			
		}
		ret = 0;
		goto out;
	}

	ret = 0;
out:
	up(&priv->wx_sem);
	return ret;
}


static int r8180_wx_get_name(struct net_device *dev, 
			     struct iw_request_info *info, 
			     union iwreq_data *wrqu, char *extra)
{
	strcpy(wrqu->name, "IEEE 802.11b");
	
	return 0;
}


static int r8180_wx_set_frag(struct net_device *dev, 
			     struct iw_request_info *info, 
			     union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;

	if (wrqu->frag.disabled)
		priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD;
	else {
		if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
		    wrqu->frag.value > MAX_FRAG_THRESHOLD)
			return -EINVAL;
		
		priv->ieee80211->fts = wrqu->frag.value & ~0x1;
	}

	return 0;
}


static int r8180_wx_get_frag(struct net_device *dev, 
			     struct iw_request_info *info, 
			     union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;

	wrqu->frag.value = priv->ieee80211->fts;
	wrqu->frag.fixed = 0;	/* no auto select */
	wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD);

	return 0;
}


static int r8180_wx_set_wap(struct net_device *dev,
			 struct iw_request_info *info,
			 union iwreq_data *awrq,
			 char *extra)
{
	int ret;
	struct r8180_priv *priv = dev->priv;
	
	down(&priv->wx_sem);
	
	
	if(priv->ieee80211->iw_mode == IW_MODE_MASTER){
		ret = -EINVAL;
		goto out;
	}
	
		
	ret = ieee80211_r8180_wx_set_wap(priv->ieee80211, info, awrq, extra);

	/*	r8180_set_mac_adr_(dev,awrq);
	*/	
	if(priv->ieee80211->iw_mode == IW_MODE_ADHOC)
		rtl8180_commit(dev);
		
out:
	up(&priv->wx_sem);
	return ret;
	
}
	

static int r8180_wx_get_wap(struct net_device *dev, 
			    struct iw_request_info *info, 
			    union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;
	
	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
	
	if(priv->ieee80211->iw_mode == IW_MODE_INFRA)
	{
		if(priv->ieee80211->link_state != WLAN_LINK_ASSOCIATED){
			memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
		}else{
			memcpy(wrqu->ap_addr.sa_data, 
		       		priv->ieee80211->ass_beacon->bssid, ETH_ALEN);
		}
	}else if(priv->ieee80211->iw_mode == IW_MODE_MONITOR){
		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
	}else if(priv->ieee80211->iw_mode == IW_MODE_ADHOC ||
		priv->ieee80211->iw_mode == IW_MODE_MASTER){
		memcpy(wrqu->ap_addr.sa_data, 
		       priv->ieee80211->beacon_cell_ssid, ETH_ALEN);
	}

	return 0;
}


static int r8180_wx_set_enc(struct net_device *dev, 
			    struct iw_request_info *info, 
			    union iwreq_data *wrqu, char *key)
{
	struct r8180_priv *priv = dev->priv;
	int ret;
	
	down(&priv->wx_sem);
	
	
#ifndef CONFIG_IEEE80211_NOWEP
	if(priv->hw_wep) ret = r8180_wx_set_key(dev,info,wrqu,key);
	else{
		DMESG("Setting SW wep key");
		ret = ieee80211_r8180_wx_set_encode(priv->ieee80211,info,wrqu,key);
	}
#else
	ret = r8180_wx_set_key(dev,info,wrqu,key);
	
#endif
	if (priv->ieee80211->iw_mode == IW_MODE_ADHOC ||
		priv->ieee80211->iw_mode == IW_MODE_MASTER)
			rtl8180_update_beacon_security(priv->dev);
			
			
	up(&priv->wx_sem);
	return ret;
}


static int r8180_wx_get_enc(struct net_device *dev, 
			    struct iw_request_info *info, 
			    union iwreq_data *wrqu, char *key)
{
	struct r8180_priv *priv = dev->priv;
	
#ifdef CONFIG_IEEE80211_NOWEP
	return -1; //FIXME: what is going on here?
	if(priv->hw_wep) return -1;
#else
	return ieee80211_r8180_wx_get_encode(priv->ieee80211, info, wrqu, key);
#endif
}


static int r8180_wx_set_scan_type(struct net_device *dev, struct iw_request_info *aa, union
 iwreq_data *wrqu, char *p){
  
 	struct r8180_priv *priv = dev->priv;
	int *parms=(int*)p;
	int mode=parms[0];
	
	priv->active_probe = mode;
	
	return 1;
}


/* added by christian */
static int r8180_wx_set_monitor_type(struct net_device *dev, struct iw_request_info *aa, union
 iwreq_data *wrqu, char *p){
  
 	struct r8180_priv *priv = dev->priv;
	int *parms=(int*)p;
	int mode=parms[0];

	if(priv->ieee80211->iw_mode != IW_MODE_MONITOR) return -1;
  	priv->prism_hdr = mode;
	if(!mode)dev->type=ARPHRD_IEEE80211;
	else dev->type=ARPHRD_IEEE80211_PRISM;

	return 0;
	
} //of         r8180_wx_set_monitor_type
/* end added christian */

static int r8180_wx_set_retry(struct net_device *dev, 
				struct iw_request_info *info, 
				union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;
	
	down(&priv->wx_sem);
	
	if (wrqu->retry.flags & IW_RETRY_LIFETIME || 
	    wrqu->retry.disabled)
		return -EINVAL;

	if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
		return -EINVAL;


	if(wrqu->retry.value > R8180_MAX_RETRY) return -EINVAL;
	
	if (wrqu->retry.flags & IW_RETRY_MAX) {
		priv->retry_rts = wrqu->retry.value;
		DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value);
	
	}else {
		priv->retry_data = wrqu->retry.value;
		DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value);
	}
	
	/* FIXME ! 
	 * We might try to write directly the TX config register
	 * or to restart just the (R)TX process.
	 * I'm unsure if whole reset is really needed
	 */

 	rtl8180_commit(dev);
	/*
	if(priv->up){
		rtl8180_rtx_disable(dev);
		rtl8180_rx_enable(dev);
		rtl8180_tx_enable(dev);
			
	}
	*/
	
	up(&priv->wx_sem);
	
	return 0;
}

static int r8180_wx_get_retry(struct net_device *dev, 
				struct iw_request_info *info, 
				union iwreq_data *wrqu, char *extra)
{
	struct r8180_priv *priv = dev->priv;
	

	wrqu->retry.disabled = 0; /* can't be disabled */

	if ((wrqu->retry.flags & IW_RETRY_TYPE) == 
	    IW_RETRY_LIFETIME) 
		return -EINVAL;
	
	if (wrqu->retry.flags & IW_RETRY_MAX) {
		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MAX;
		wrqu->retry.value = priv->retry_rts;
	} else {
		wrqu->retry.flags = IW_RETRY_LIMIT & IW_RETRY_MIN;
		wrqu->retry.value = priv->retry_data;
	}
	//DMESG("returning %d",wrqu->retry.value);
	

	return 0;
}


static int dummy(struct net_device *dev, struct iw_request_info *a,
		 union iwreq_data *wrqu,char *b)
{
	return -1;
}


static iw_handler r8180_wx_handlers[] =
{
        NULL,                     /* SIOCSIWCOMMIT */
        r8180_wx_get_name,   	  /* SIOCGIWNAME */
        dummy,                    /* SIOCSIWNWID */
        dummy,                    /* SIOCGIWNWID */
        r8180_wx_set_freq,        /* SIOCSIWFREQ */
        r8180_wx_get_freq,        /* SIOCGIWFREQ */
        r8180_wx_set_mode,        /* SIOCSIWMODE */
        r8180_wx_get_mode,        /* SIOCGIWMODE */
        dummy,                    /* SIOCSIWSENS */
        dummy,                    /* SIOCGIWSENS */
        NULL,                     /* SIOCSIWRANGE */
        rtl8180_wx_get_range,	  /* SIOCGIWRANGE */
        NULL,                     /* SIOCSIWPRIV */
        NULL,                     /* SIOCGIWPRIV */
        NULL,                     /* SIOCSIWSTATS */
        NULL,                     /* SIOCGIWSTATS */
        dummy,                    /* SIOCSIWSPY */
        dummy,                    /* SIOCGIWSPY */
        NULL,                     /* SIOCGIWTHRSPY */
        NULL,                     /* SIOCWIWTHRSPY */
        r8180_wx_set_wap,      	  /* SIOCSIWAP */
        r8180_wx_get_wap,         /* SIOCGIWAP */
        NULL,                     /* -- hole -- */
        dummy,                     /* SIOCGIWAPLIST -- depricated */
        r8180_wx_set_scan,        /* SIOCSIWSCAN */
        r8180_wx_get_scan,        /* SIOCGIWSCAN */
        r8180_wx_set_essid,       /* SIOCSIWESSID */
        r8180_wx_get_essid,       /* SIOCGIWESSID */
        dummy,                    /* SIOCSIWNICKN */
        dummy,                    /* SIOCGIWNICKN */
        NULL,                     /* -- hole -- */
        NULL,                     /* -- hole -- */
        r8180_wx_set_rate,        /* SIOCSIWRATE */
        r8180_wx_get_rate,        /* SIOCGIWRATE */
        dummy,                    /* SIOCSIWRTS */
        dummy,                    /* SIOCGIWRTS */
        r8180_wx_set_frag,        /* SIOCSIWFRAG */
        r8180_wx_get_frag,        /* SIOCGIWFRAG */
        dummy,                    /* SIOCSIWTXPOW */
        dummy,                    /* SIOCGIWTXPOW */
        r8180_wx_set_retry,       /* SIOCSIWRETRY */
        r8180_wx_get_retry,       /* SIOCGIWRETRY */
        r8180_wx_set_enc,         /* SIOCSIWENCODE */
        r8180_wx_get_enc,         /* SIOCGIWENCODE */
        dummy,                    /* SIOCSIWPOWER */
        dummy,                    /* SIOCGIWPOWER */
}; 


static const struct iw_priv_args r8180_private_args[] = { 
	{
		SIOCIWFIRSTPRIV + 0x0, 
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor" 
	}, 
	{
		SIOCIWFIRSTPRIV + 0x1, 
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" 
	}, 
	{
		SIOCIWFIRSTPRIV + 0x2, 
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debugtx" 
	}, 
	{
		SIOCIWFIRSTPRIV + 0x3, 
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beaconint" 
	},
	/* added by christian */
	{
		SIOCIWFIRSTPRIV + 0x4,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "prismhdr"
	},
	/* end added by christian */
	{
		SIOCIWFIRSTPRIV + 0x5,
		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan"
	
	}
};


static iw_handler r8180_private_handler[] = {
	r8180_wx_set_monitor,  /* SIOCIWFIRSTPRIV */
	r8180_wx_set_crcmon,   /*SIOCIWSECONDPRIV*/
	r8180_debug_tx,
	r8180_set_beaconinterval,
	r8180_wx_set_monitor_type,
	r8180_wx_set_scan_type,
};

#if WIRELESS_EXT > 17

static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev)
{
       struct r8180_priv *priv = dev->priv;

       return &priv->wstats;
}


struct iw_handler_def  r8180_wx_handlers_def={
	sizeof(r8180_wx_handlers) / sizeof(iw_handler),
	sizeof(r8180_private_handler) / sizeof(iw_handler),
 	sizeof(r8180_private_args) / sizeof(struct iw_priv_args),
	r8180_wx_handlers,
	r8180_private_handler,
	(struct iw_priv_args *)r8180_private_args,	
        0,
        (struct iw_statistics *)r8180_get_wireless_stats
};

#else

struct iw_handler_def  r8180_wx_handlers_def={
	.standard r8180_wx_handlers,
	.num_standard = sizeof(r8180_wx_handlers) / sizeof(iw_handler),
	.private = r8180_private_handler,
	.num_private = sizeof(r8180_private_handler) / sizeof(iw_handler),
 	.num_private_args = sizeof(r8180_private_args) / sizeof(struct iw_priv_args),
	.private_args = (struct iw_priv_args *)r8180_private_args,	
};

#endif
