/*
  Copyright 2004, 2005 Jean-Baptiste Note
  Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
  Copyright (c) 2006 Red Hat, Inc.

  This file is part of prism54usb.

  prism54usb is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  prism54usb is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with prism54usb; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#include <linux/wireless.h>
#include <linux/netdevice.h>	/* needed by iw_handler */
#include <linux/if_arp.h>
#include <net/iw_handler.h>

#include "islsm_ioctl.h"
#include "isl_sm.h"
#include "islsm_log.h"

#ifdef MADWIFI
#include "linux/version.h"
#include "net80211/ieee80211_linux.h"
#else
#include <linux/etherdevice.h>
#include <net/ieee80211softmac_wx.h>
#endif				/* MADWIFI */

/*
 * private ioctl to allow experimentation
 */

#ifndef MADWIFI
#define MAX_PKT_LEN 200

static int
islsm_ioctl_sendannouncedpkt(struct net_device *netdev,
    struct iw_request_info *unused, union iwreq_data *u, char *extra)
{
	struct islsm *islsm = ISLSM_OF_NETDEV(netdev);
	char *data;
	size_t pktsize;
	int err = 0;

	FN_ENTER;

	if (u == 0) {
		err = -ENOTSUPP;
		goto exit;
	}

	pktsize = u->data.length;

	if (pktsize > MAX_PKT_LEN) {
		err = -ENOTSUPP;
		goto exit;
	}

	data = u->data.pointer;

	/* note : this does not work with second-generation devices */
	islsm_outofband_msg(islsm, data, pktsize);
      exit:
	FN_EXIT1(err);
	return err;
}
#endif				/* MADWIFI */

/* add ioctls to change the verbosity of the driver */

#define SUPPORTED_WIRELESS_EXT                  16

#ifdef CONFIG_NET_WIRELESS

#ifndef MADWIFI

/**** WARNING *****/
/* _ALL_ of these calls are bogus except for set_channel_freq */
/* I expect to complete statistics soon enough */

struct iw_statistics *islsm_wireless_stats(struct net_device *ndev)
{
	struct islsm *priv = ISLSM_OF_NETDEV(ndev);

	/* completely bogus */
	return &priv->iwstatistics;
}

static int
prism54_commit(struct net_device *ndev, struct iw_request_info *info,
    union iwreq_data *wrqu, char *extra)
{
	return 0;
}

static int
prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
    union iwreq_data *data, char *extra)
{
	char *capabilities;

	capabilities = "IEEE 802.11b";		/* Default. Add 'a' later. */

	strncpy(data->name, capabilities, IFNAMSIZ);
	return 0;
}

static int
prism54_set_freq(struct net_device *netdev, struct iw_request_info *info,
		 union iwreq_data *data, char *extra)
{
	struct iw_freq *fwrq = &data->freq;
	struct islsm *islsm = ISLSM_OF_NETDEV(netdev);
	unsigned int c;

	if (fwrq->m < 1000 && fwrq->m >= 1 && fwrq->m <= ISLSM_NR_CHANNELS) {
		/* we have a valid channel number */
		c = fwrq->m;
	} else {
		if (fwrq->m <= 0)
			return -EINVAL;
		c = islsm_freq_to_chan(fwrq->m);
		if (c == 0 || c > ISLSM_NR_CHANNELS)
			return -EINVAL;
	}

	/* XXX Semaphore here */
	islsm_freq_change(islsm,
			  c, islsm_chan_to_freq(c),
			  ISLSM_TX_CONTROL_CHANNEL_MAGIC1_SCAN,
			  ISLSM_TX_CONTROL_CHANNEL_MAGIC2_SCAN);
	islsm->last_chan = c;
	return 0;
}

static int prism54_get_freq(struct net_device *netdev,
   struct iw_request_info *info, union iwreq_data *data, char *extra)
{
	struct iw_freq *fwrq = &data->freq;
	struct islsm *islsm = ISLSM_OF_NETDEV(netdev);

	memset(fwrq, 0, sizeof(struct iw_freq));
	fwrq->m = islsm->last_chan;
	fwrq->e = 0;
	fwrq->flags = 1;	/* It was a fixed setting */
	return 0;
}

static int
prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
		 union iwreq_data *data, char *extra)
{
	struct islsm *islsm = ISLSM_OF_NETDEV(ndev);
	int mode = data->mode;
	int err = 0;

	/* XXX Locking */
	switch (mode) {
	case IW_MODE_MONITOR:
		islsm->ieee->iw_mode = mode;
		ndev->type = ARPHRD_IEEE80211;
		break;

	case IW_MODE_ADHOC:
	case IW_MODE_INFRA:
	/* case IW_MODE_MASTER: */ /* XXX support AP mode */
		islsm->ieee->iw_mode = mode;
		ndev->type = ARPHRD_ETHER;
		break;

	default:
		return -EINVAL;
	}

	if (ndev->flags & IFF_RUNNING) {
		err = islsm_mode_set_filter(ndev, mode);
		if (err)
			printk(KERN_WARNING "error setting filter : %i", err);
	}

	return 0;
}

static int
prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
		 union iwreq_data *data, char *extra)
{
	struct islsm *islsm = ISLSM_OF_NETDEV(ndev);
	unsigned long flags;

	spin_lock_irqsave(&islsm->ieee->lock, flags);
	data->mode = islsm->ieee->iw_mode;
	spin_unlock_irqrestore(&islsm->ieee->lock, flags);
	return 0;
}

/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
 * emit data if (sensitivity > rssi - noise) (in dBm).
 * prism54_set_sens does not seem to work.
 */

static int
prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
		 struct iw_param *vwrq, char *extra)
{
/* 	islpci_private *priv = ISLSM_OF_NETDEV(ndev); */
/* 	u32 sens; */

/* 	/\* by default  the card sets this to 20. *\/ */
/* 	sens = vwrq->disabled ? 20 : vwrq->value; */

/* 	return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); */
	return 0;
}

static int
prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
		 struct iw_param *vwrq, char *extra)
{
/* 	islpci_private *priv = ISLSM_OF_NETDEV(ndev); */
/* 	union oid_res_t r; */
/* 	int rvalue; */

/* 	rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); */

	vwrq->value = 0;
	vwrq->disabled = (vwrq->value == 0);
	vwrq->fixed = 1;

	return 0;
}

static int
prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
		  struct iw_point *dwrq, char *extra)
{
	struct iw_range *range = (struct iw_range *) extra;

	memset(range, 0, sizeof (struct iw_range));
	dwrq->length = sizeof (struct iw_range);

	/* set the wireless extension version number */
	range->we_version_source = SUPPORTED_WIRELESS_EXT;
	range->we_version_compiled = WIRELESS_EXT;

	/* Now the encoding capabilities */
	range->num_encoding_sizes = 3;
	/* 64(40) bits WEP */
	range->encoding_size[0] = 5;
	/* 128(104) bits WEP */
	range->encoding_size[1] = 13;
	/* 256 bits for WPA-PSK */
	range->encoding_size[2] = 32;
	/* 4 keys are allowed */
	range->max_encoding_tokens = 4;

	/* we don't know the quality range... */
	range->max_qual.level = 0;
	range->max_qual.noise = 0;
	range->max_qual.qual = 0;
	/* these value describe an average quality. Needs more tweaking... */
	range->avg_qual.level = -80;	/* -80 dBm */
	range->avg_qual.noise = 0;	/* don't know what to put here */
	range->avg_qual.qual = 0;

	range->sensitivity = 200;

	/* retry limit capabilities */
	range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
	range->retry_flags = IW_RETRY_LIMIT;
	range->r_time_flags = IW_RETRY_LIFETIME;

	/* I don't know the range. Put stupid things here */
	range->min_retry = 1;
	range->max_retry = 65535;
	range->min_r_time = 1024;
	range->max_r_time = 65535 * 1024;

	/* txpower is supported in dBm's */
	range->txpower_capa = IW_TXPOW_DBM;

	return 0;
}

static int
prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
		 union iwreq_data *data, char *extra)
{
	/* We only do a passive scan for now. */
	return 0;
}

static const iw_handler prism54_handler[] = {
	prism54_commit,			/* SIOCSIWCOMMIT */
	prism54_get_name,		/* SIOCGIWNAME */
	NULL,				/* SIOCSIWNWID */
	NULL,				/* SIOCGIWNWID */
	prism54_set_freq,		/* SIOCSIWFREQ */
	prism54_get_freq,		/* SIOCGIWFREQ */
	prism54_set_mode,		/* SIOCSIWMODE */
	prism54_get_mode,		/* SIOCGIWMODE */
	(iw_handler) prism54_set_sens,	/* SIOCSIWSENS */
	(iw_handler) prism54_get_sens,	/* SIOCGIWSENS */
	NULL,				/* SIOCSIWRANGE */
	(iw_handler) prism54_get_range,	/* SIOCGIWRANGE */
	NULL,				/* SIOCSIWPRIV */
	NULL,				/* SIOCGIWPRIV */
	NULL,				/* SIOCSIWSTATS */
	NULL,				/* SIOCGIWSTATS */
	NULL,	//      prism54_set_spy,        /* SIOCSIWSPY */
	NULL,	//      iw_handler_get_spy,     /* SIOCGIWSPY */
	NULL,	//      iw_handler_set_thrspy,  /* SIOCSIWTHRSPY */
	NULL,	//      iw_handler_get_thrspy,  /* SIOCGIWTHRSPY */
	ieee80211softmac_wx_set_wap,	/* SIOCSIWAP */
	ieee80211softmac_wx_get_wap,	/* SIOCGIWAP */
	NULL,				/* 0x16 -- hole -- */
	NULL,				/* SIOCGIWAPLIST depreciated */
	prism54_set_scan,		/* SIOCSIWSCAN */
	ieee80211softmac_wx_get_scan_results,	/* SIOCGIWSCAN */
	ieee80211softmac_wx_set_essid,	/* SIOCSIWESSID */
	ieee80211softmac_wx_get_essid,	/* SIOCGIWESSID */
	NULL,	//      (iw_handler) prism54_set_nick,  /* SIOCSIWNICKN */
	NULL,	//      (iw_handler) prism54_get_nick,  /* SIOCGIWNICKN */
	NULL,				/* 0x1E -- hole -- */
	NULL,				/* 0x1F -- hole -- */
	NULL,	//      (iw_handler) prism54_set_rate,  /* SIOCSIWRATE */
	NULL,	//      (iw_handler) prism54_get_rate,  /* SIOCGIWRATE */
	NULL,	//      (iw_handler) prism54_set_rts,   /* SIOCSIWRTS */
	NULL,	//      (iw_handler) prism54_get_rts,   /* SIOCGIWRTS */
	NULL,	//      (iw_handler) prism54_set_frag,  /* SIOCSIWFRAG */
	NULL,	//      (iw_handler) prism54_get_frag,  /* SIOCGIWFRAG */
	NULL,	//      (iw_handler) prism54_set_txpower,       /* SIOCSIWTXPOW */
	NULL,	//      (iw_handler) prism54_get_txpower,       /* SIOCGIWTXPOW */
	NULL,	//      (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */
	NULL,	//      (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */
	NULL,	//      (iw_handler) prism54_set_encode,        /* SIOCSIWENCODE */
	NULL,	//      (iw_handler) prism54_get_encode,        /* SIOCGIWENCODE */
	NULL,				/* SIOCSIWPOWER */
	NULL,				/* SIOCGIWPOWER */
	NULL,				/* 0x2E -- hole -- */
	NULL,				/* 0x2F -- hole -- */
	NULL,				/* SIOCSIWGENIE	*/
	NULL,				/* SIOCGIWGENIE	*/
	NULL,				/* SIOCSIWAUTH */
	NULL,				/* SIOCGIWAUTH */
	NULL,				/* SIOCSIWENCODEEXT */
	NULL,				/* SIOCGIWENCODEEXT */
	NULL,				/* SIOCSIWPMKSA	*/
};

/* XXX MAX_PKT_LEN use below is bogus - masking with decimal 200 */
static const struct iw_priv_args prism54_private_args[] = {
	[0] = {			/* args for islsm_ioctl_sendannouncedpkt */
	       .cmd = SIOCIWFIRSTPRIV,
	       .set_args = ((IW_PRIV_TYPE_MASK & IW_PRIV_TYPE_BYTE) |	/* type of args */
			    (IW_PRIV_SIZE_MASK & MAX_PKT_LEN))	/* max number of args */
	       &(~IW_PRIV_SIZE_FIXED),	/* size is not fixed */
	       .get_args = 0,	/* Type and number of args */
	       .name = "set_announcedpkt",	/* Name of the extension */
	       },
};

static const iw_handler prism54_private_handler[] = {
	islsm_ioctl_sendannouncedpkt,		/* SIOCWFIRSTPRIV+15 */
};

struct iw_handler_def islsm_iw_handler_def = {
	.num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
	.num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
	.num_private_args =
	    sizeof (prism54_private_args) / sizeof (prism54_private_args[0]),
	.standard = prism54_handler,
	.private = prism54_private_handler,
	.private_args = prism54_private_args,
	.get_wireless_stats = islsm_wireless_stats,
};

#else				/* MADWIFI */

/*
 * Return wireless extensions statistics.
 */
struct iw_statistics *
islsm_wireless_stats(struct net_device *dev)
{
	struct islsm *sc = dev->priv;
	struct ieee80211com *ic = &sc->sc_ic;
	struct iw_statistics *is = &sc->iwstatistics;

	ieee80211_iw_getstats(ic, is);
	/* add in statistics maintained by the driver */
/* 	is->discard.code += sc->sc_stats.ast_rx_badcrypt; */
/* 	is->discard.retries += sc->sc_stats.ast_tx_xretries; */
/* 	is->discard.misc += sc->sc_stats.ast_tx_encap */
/* 			 + sc->sc_stats.ast_tx_nonode */
/* 			 + sc->sc_stats.ast_tx_xretries */
/* 			 + sc->sc_stats.ast_tx_fifoerr */
/* 			 + sc->sc_stats.ast_tx_filtered */
/* 			 + sc->sc_stats.ast_tx_nobuf */
/* 			 + sc->sc_stats.ast_tx_nobufmgt; */
/* 			 ; */
/* 	is->miss.beacon = sc->sc_stats.ast_bmiss; */

	return &sc->iwstatistics;
}

#include <net/iw_handler.h>
/*
 * Bounce functions to get to the 802.11 code. These are
 * necessary for now because wireless extensions operations
 * are done on the underlying device and not the 802.11 instance.
 * This will change when there can be multiple 802.11 instances
 * associated with a device and we must have a net_device for
 * each so we can manipulate them individually.
 */
#define	ISLSM_CHAR_BOUNCE(name)						\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 char *erq, char *extra)				\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}
#define	ISLSM_POINT_BOUNCE(name)						\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 struct iw_point *erq, char *extra)			\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}
#define	ISLSM_PARAM_BOUNCE(name)						\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 struct iw_param *erq, char *extra)			\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}
#define	ISLSM_SOCKADDR_BOUNCE(name)					\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 struct sockaddr *erq, char *extra)			\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}
#define	ISLSM_FREQ_BOUNCE(name)						\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 struct iw_freq *erq, char *extra)			\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}
#define	ISLSM_U32_BOUNCE(name)						\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 __u32 *erq, char *extra)				\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}
#define	ISLSM_VOID_BOUNCE(name)						\
static int								\
islsm_ioctl_##name(struct net_device *dev, struct iw_request_info *info,	\
		 void *erq, char *extra)				\
{									\
	struct islsm *sc = dev->priv;				\
	return ieee80211_ioctl_##name(&sc->sc_ic, info, erq, extra);	\
}

ISLSM_CHAR_BOUNCE(giwname)
    ISLSM_POINT_BOUNCE(siwencode)
    ISLSM_POINT_BOUNCE(giwencode)
    ISLSM_PARAM_BOUNCE(siwrate)
    ISLSM_PARAM_BOUNCE(giwrate)
    ISLSM_PARAM_BOUNCE(siwsens)
    ISLSM_PARAM_BOUNCE(giwsens)
    ISLSM_PARAM_BOUNCE(siwrts)
    ISLSM_PARAM_BOUNCE(giwrts)
    ISLSM_PARAM_BOUNCE(siwfrag)
    ISLSM_PARAM_BOUNCE(giwfrag)
    ISLSM_SOCKADDR_BOUNCE(siwap)
    ISLSM_SOCKADDR_BOUNCE(giwap)
    ISLSM_POINT_BOUNCE(siwnickn)
    ISLSM_POINT_BOUNCE(giwnickn)
    ISLSM_FREQ_BOUNCE(siwfreq)
    ISLSM_FREQ_BOUNCE(giwfreq)
    ISLSM_POINT_BOUNCE(siwessid)
    ISLSM_POINT_BOUNCE(giwessid)
    ISLSM_POINT_BOUNCE(giwrange)
    ISLSM_U32_BOUNCE(siwmode)
    ISLSM_U32_BOUNCE(giwmode)
    ISLSM_PARAM_BOUNCE(siwpower)
    ISLSM_PARAM_BOUNCE(giwpower)
    ISLSM_PARAM_BOUNCE(siwretry)
    ISLSM_PARAM_BOUNCE(giwretry)
    ISLSM_PARAM_BOUNCE(siwtxpow)
    ISLSM_PARAM_BOUNCE(giwtxpow)
    ISLSM_POINT_BOUNCE(iwaplist)
#ifdef SIOCGIWSCAN
    ISLSM_POINT_BOUNCE(siwscan)
    ISLSM_POINT_BOUNCE(giwscan)
#endif
    ISLSM_VOID_BOUNCE(setparam)
    ISLSM_VOID_BOUNCE(getparam)
    ISLSM_VOID_BOUNCE(setkey)
    ISLSM_VOID_BOUNCE(delkey)
    ISLSM_VOID_BOUNCE(setmlme)
    ISLSM_VOID_BOUNCE(setoptie)
    ISLSM_VOID_BOUNCE(getoptie)
    ISLSM_VOID_BOUNCE(addmac)
    ISLSM_VOID_BOUNCE(delmac)
    ISLSM_VOID_BOUNCE(chanlist)

/* Structures to export the Wireless Handlers */
static const iw_handler islsm_handlers[] = {
	(iw_handler) NULL,	/* SIOCSIWCOMMIT */
	(iw_handler) islsm_ioctl_giwname,	/* SIOCGIWNAME */
	(iw_handler) NULL,	/* SIOCSIWNWID */
	(iw_handler) NULL,	/* SIOCGIWNWID */
	(iw_handler) islsm_ioctl_siwfreq,	/* SIOCSIWFREQ */
	(iw_handler) islsm_ioctl_giwfreq,	/* SIOCGIWFREQ */
	(iw_handler) islsm_ioctl_siwmode,	/* SIOCSIWMODE */
	(iw_handler) islsm_ioctl_giwmode,	/* SIOCGIWMODE */
	(iw_handler) islsm_ioctl_siwsens,	/* SIOCSIWSENS */
	(iw_handler) islsm_ioctl_giwsens,	/* SIOCGIWSENS */
	(iw_handler) NULL /* not used */ ,	/* SIOCSIWRANGE */
	(iw_handler) islsm_ioctl_giwrange,	/* SIOCGIWRANGE */
	(iw_handler) NULL /* not used */ ,	/* SIOCSIWPRIV */
	(iw_handler) NULL /* kernel code */ ,	/* SIOCGIWPRIV */
	(iw_handler) NULL /* not used */ ,	/* SIOCSIWSTATS */
	(iw_handler) NULL /* kernel code */ ,	/* SIOCGIWSTATS */
	(iw_handler) NULL,	/* SIOCSIWSPY */
	(iw_handler) NULL,	/* SIOCGIWSPY */
	(iw_handler) NULL,	/* -- hole -- */
	(iw_handler) NULL,	/* -- hole -- */
	(iw_handler) islsm_ioctl_siwap,	/* SIOCSIWAP */
	(iw_handler) islsm_ioctl_giwap,	/* SIOCGIWAP */
	(iw_handler) NULL,	/* -- hole -- */
	(iw_handler) islsm_ioctl_iwaplist,	/* SIOCGIWAPLIST */
#ifdef SIOCGIWSCAN
	(iw_handler) islsm_ioctl_siwscan,	/* SIOCSIWSCAN */
	(iw_handler) islsm_ioctl_giwscan,	/* SIOCGIWSCAN */
#else
	(iw_handler) NULL,	/* SIOCSIWSCAN */
	(iw_handler) NULL,	/* SIOCGIWSCAN */
#endif				/* SIOCGIWSCAN */
	(iw_handler) islsm_ioctl_siwessid,	/* SIOCSIWESSID */
	(iw_handler) islsm_ioctl_giwessid,	/* SIOCGIWESSID */
	(iw_handler) islsm_ioctl_siwnickn,	/* SIOCSIWNICKN */
	(iw_handler) islsm_ioctl_giwnickn,	/* SIOCGIWNICKN */
	(iw_handler) NULL,	/* -- hole -- */
	(iw_handler) NULL,	/* -- hole -- */
	(iw_handler) islsm_ioctl_siwrate,	/* SIOCSIWRATE */
	(iw_handler) islsm_ioctl_giwrate,	/* SIOCGIWRATE */
	(iw_handler) islsm_ioctl_siwrts,	/* SIOCSIWRTS */
	(iw_handler) islsm_ioctl_giwrts,	/* SIOCGIWRTS */
	(iw_handler) islsm_ioctl_siwfrag,	/* SIOCSIWFRAG */
	(iw_handler) islsm_ioctl_giwfrag,	/* SIOCGIWFRAG */
	(iw_handler) islsm_ioctl_siwtxpow,	/* SIOCSIWTXPOW */
	(iw_handler) islsm_ioctl_giwtxpow,	/* SIOCGIWTXPOW */
	(iw_handler) islsm_ioctl_siwretry,	/* SIOCSIWRETRY */
	(iw_handler) islsm_ioctl_giwretry,	/* SIOCGIWRETRY */
	(iw_handler) islsm_ioctl_siwencode,	/* SIOCSIWENCODE */
	(iw_handler) islsm_ioctl_giwencode,	/* SIOCGIWENCODE */
	(iw_handler) islsm_ioctl_siwpower,	/* SIOCSIWPOWER */
	(iw_handler) islsm_ioctl_giwpower,	/* SIOCGIWPOWER */
};
static const iw_handler islsm_priv_handlers[] = {
	(iw_handler) islsm_ioctl_setparam,	/* SIOCWFIRSTPRIV+0 */
	(iw_handler) islsm_ioctl_getparam,	/* SIOCWFIRSTPRIV+1 */
	(iw_handler) islsm_ioctl_setkey,	/* SIOCWFIRSTPRIV+2 */
	(iw_handler) NULL,	/* SIOCWFIRSTPRIV+3 */
	(iw_handler) islsm_ioctl_delkey,	/* SIOCWFIRSTPRIV+4 */
	(iw_handler) NULL,	/* SIOCWFIRSTPRIV+5 */
	(iw_handler) islsm_ioctl_setmlme,	/* SIOCWFIRSTPRIV+6 */
	(iw_handler) NULL,	/* SIOCWFIRSTPRIV+7 */
	(iw_handler) islsm_ioctl_setoptie,	/* SIOCWFIRSTPRIV+8 */
	(iw_handler) islsm_ioctl_getoptie,	/* SIOCWFIRSTPRIV+9 */
	(iw_handler) islsm_ioctl_addmac,	/* SIOCWFIRSTPRIV+10 */
	(iw_handler) NULL,	/* SIOCWFIRSTPRIV+11 */
	(iw_handler) islsm_ioctl_delmac,	/* SIOCWFIRSTPRIV+12 */
	(iw_handler) NULL,	/* SIOCWFIRSTPRIV+13 */
	(iw_handler) islsm_ioctl_chanlist,	/* SIOCWFIRSTPRIV+14 */
};

struct iw_handler_def islsm_iw_handler_def = {
#define	N(a)	(sizeof (a) / sizeof (a[0]))
	.standard = (iw_handler *) islsm_handlers,
	.num_standard = N(islsm_handlers),
	.private = (iw_handler *) islsm_priv_handlers,
	.num_private = N(islsm_priv_handlers),
#undef N
};

#endif				/* MADWIFI */

#endif				/* CONFIG_NET_WIRELESS */
