Commit a5220ff4 authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Jeff Garzik

Update (ancient) wireless net drivers netwave_cs, wavelan,

and wavelan_cs to new wireless API.
parent 74a4e27a
......@@ -63,6 +63,9 @@
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif
#include <pcmcia/version.h>
......@@ -269,6 +272,16 @@ static dev_link_t *dev_list;
because they generally can't be allocated dynamically.
*/
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* Part of iw_handler prototype we need */
struct iw_request_info
{
__u16 cmd; /* Wireless Extension command */
__u16 flags; /* More to come ;-) */
};
/* Wireless Extension Backward compatibility - Jean II
* If the new wireless device private ioctl range is not defined,
* default to standard device private ioctl range */
......@@ -276,8 +289,11 @@ static dev_link_t *dev_list;
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
#endif /* SIOCIWFIRSTPRIV */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV /* Site Survey Snapshot */
/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/
#else /* WIRELESS_EXT <= 12 */
static const struct iw_handler_def netwave_handler_def;
#endif /* WIRELESS_EXT <= 12 */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */
#define MAX_ESA 10
......@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void)
/* wireless extensions */
#ifdef WIRELESS_EXT
dev->get_wireless_stats = &netwave_get_wireless_stats;
#endif
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def;
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */
dev->do_ioctl = &netwave_ioctl;
dev->tx_timeout = &netwave_watchdog;
......@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void)
}
} /* netwave_flush_stale_links */
/*
* Wireless Handler : get protocol name
*/
static int netwave_get_name(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
strcpy(wrqu->name, "Netwave");
return 0;
}
/*
* Wireless Handler : set Network ID
*/
static int netwave_set_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long flags;
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
/* Disable interrupts & save flags */
save_flags(flags);
cli();
#if WIRELESS_EXT > 8
if(!wrqu->nwid.disabled) {
domain = wrqu->nwid.value;
#else /* WIRELESS_EXT > 8 */
if(wrqu->nwid.on) {
domain = wrqu->nwid.nwid;
#endif /* WIRELESS_EXT > 8 */
printk( KERN_DEBUG "Setting domain to 0x%x%02x\n",
(domain >> 8) & 0x01, domain & 0xff);
wait_WOC(iobase);
writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
}
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return 0;
}
/*
* Wireless Handler : get Network ID
*/
static int netwave_get_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
#if WIRELESS_EXT > 8
wrqu->nwid.value = domain;
wrqu->nwid.disabled = 0;
wrqu->nwid.fixed = 1;
#else /* WIRELESS_EXT > 8 */
wrqu->nwid.nwid = domain;
wrqu->nwid.on = 1;
#endif /* WIRELESS_EXT > 8 */
return 0;
}
/*
* Wireless Handler : set scramble key
*/
static int netwave_set_scramble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *key)
{
unsigned long flags;
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
/* Disable interrupts & save flags */
save_flags(flags);
cli();
scramble_key = (key[0] << 8) | key[1];
wait_WOC(iobase);
writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return 0;
}
/*
* Wireless Handler : get scramble key
*/
static int netwave_get_scramble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *key)
{
key[1] = scramble_key & 0xff;
key[0] = (scramble_key>>8) & 0xff;
#if WIRELESS_EXT > 8
wrqu->encoding.flags = IW_ENCODE_ENABLED;
wrqu->encoding.length = 2;
#else /* WIRELESS_EXT > 8 */
wrqu->encoding.method = 1;
#endif /* WIRELESS_EXT > 8 */
return 0;
}
#if WIRELESS_EXT > 8
/*
* Wireless Handler : get mode
*/
static int netwave_get_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
if(domain & 0x100)
wrqu->mode = IW_MODE_INFRA;
else
wrqu->mode = IW_MODE_ADHOC;
return 0;
}
#endif /* WIRELESS_EXT > 8 */
/*
* Wireless Handler : get range info
*/
static int netwave_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;
int ret = 0;
/* Set the length (very important for backward compatibility) */
wrqu->data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(range, 0, sizeof(struct iw_range));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9; /* Nothing for us in v10 and v11 */
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range->throughput = 450 * 1000; /* don't argue on this ! */
range->min_nwid = 0x0000;
range->max_nwid = 0x01FF;
range->num_channels = range->num_frequency = 0;
range->sensitivity = 0x3F;
range->max_qual.qual = 255;
range->max_qual.level = 255;
range->max_qual.noise = 0;
#if WIRELESS_EXT > 7
range->num_bitrates = 1;
range->bitrate[0] = 1000000; /* 1 Mb/s */
#endif /* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
range->encoding_size[0] = 2; /* 16 bits scrambling */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
#endif /* WIRELESS_EXT > 8 */
return ret;
}
/*
* Wireless Private Handler : get snapshot
*/
static int netwave_get_snap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long flags;
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
/* Disable interrupts & save flags */
save_flags(flags);
cli();
/* Take snapshot of environment */
netwave_snapshot( priv, ramBase, iobase);
wrqu->data.length = priv->nss.length;
memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey));
priv->lastExec = jiffies;
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return(0);
}
/*
* Structures to export the Wireless Handlers
* This is the stuff that are treated the wireless extensions (iwconfig)
*/
static const struct iw_priv_args netwave_private_args[] = {
/*{ cmd, set_args, get_args, name } */
{ SIOCGIPSNAP, 0,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey),
"getsitesurvey" },
};
#if WIRELESS_EXT > 12
static const iw_handler netwave_handler[] =
{
NULL, /* SIOCSIWNAME */
netwave_get_name, /* SIOCGIWNAME */
netwave_set_nwid, /* SIOCSIWNWID */
netwave_get_nwid, /* SIOCGIWNWID */
NULL, /* SIOCSIWFREQ */
NULL, /* SIOCGIWFREQ */
NULL, /* SIOCSIWMODE */
netwave_get_mode, /* SIOCGIWMODE */
NULL, /* SIOCSIWSENS */
NULL, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
netwave_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
NULL, /* SIOCSIWSPY */
NULL, /* SIOCGIWSPY */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWAP */
NULL, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWESSID */
NULL, /* SIOCGIWESSID */
NULL, /* SIOCSIWNICKN */
NULL, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWRATE */
NULL, /* SIOCGIWRATE */
NULL, /* SIOCSIWRTS */
NULL, /* SIOCGIWRTS */
NULL, /* SIOCSIWFRAG */
NULL, /* SIOCGIWFRAG */
NULL, /* SIOCSIWTXPOW */
NULL, /* SIOCGIWTXPOW */
NULL, /* SIOCSIWRETRY */
NULL, /* SIOCGIWRETRY */
netwave_set_scramble, /* SIOCSIWENCODE */
netwave_get_scramble, /* SIOCGIWENCODE */
};
static const iw_handler netwave_private_handler[] =
{
NULL, /* SIOCIWFIRSTPRIV */
netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */
};
static const struct iw_handler_def netwave_handler_def =
{
num_standard: sizeof(netwave_handler)/sizeof(iw_handler),
num_private: sizeof(netwave_private_handler)/sizeof(iw_handler),
num_private_args: sizeof(netwave_private_args)/sizeof(struct iw_priv_args),
standard: (iw_handler *) netwave_handler,
private: (iw_handler *) netwave_private_handler,
private_args: (struct iw_priv_args *) netwave_private_args,
};
#endif /* WIRELESS_EXT > 12 */
/*
* Function netwave_ioctl (dev, rq, cmd)
*
......@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
struct ifreq *rq, /* Data passed */
int cmd) /* Ioctl number */
{
unsigned long flags;
int ret = 0;
#ifdef WIRELESS_EXT
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
#if WIRELESS_EXT <= 12
struct iwreq *wrq = (struct iwreq *) rq;
#endif
#endif
DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
/* Disable interrupts & save flags */
save_flags(flags);
cli();
/* Look what is the request */
switch(cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */
#ifdef WIRELESS_EXT
#if WIRELESS_EXT <= 12
case SIOCGIWNAME:
/* Get name */
strcpy(wrq->u.name, "Netwave");
netwave_get_name(dev, NULL, &(wrq->u), NULL);
break;
case SIOCSIWNWID:
/* Set domain */
#if WIRELESS_EXT > 8
if(!wrq->u.nwid.disabled) {
domain = wrq->u.nwid.value;
#else /* WIRELESS_EXT > 8 */
if(wrq->u.nwid.on) {
domain = wrq->u.nwid.nwid;
#endif /* WIRELESS_EXT > 8 */
printk( KERN_DEBUG "Setting domain to 0x%x%02x\n",
(domain >> 8) & 0x01, domain & 0xff);
wait_WOC(iobase);
writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
} break;
ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWNWID:
/* Read domain*/
#if WIRELESS_EXT > 8
wrq->u.nwid.value = domain;
wrq->u.nwid.disabled = 0;
wrq->u.nwid.fixed = 1;
#else /* WIRELESS_EXT > 8 */
wrq->u.nwid.nwid = domain;
wrq->u.nwid.on = 1;
#endif /* WIRELESS_EXT > 8 */
ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL);
break;
#if WIRELESS_EXT > 8 /* Note : The API did change... */
case SIOCGIWENCODE:
......@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
char key[2];
key[1] = scramble_key & 0xff;
key[0] = (scramble_key>>8) & 0xff;
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
wrq->u.encoding.length = 2;
ret = netwave_get_scramble(dev, NULL, &(wrq->u), key);
if(copy_to_user(wrq->u.encoding.pointer, key, 2))
ret = -EFAULT;
}
......@@ -681,79 +966,31 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
ret = -EFAULT;
break;
}
scramble_key = (key[0] << 8) | key[1];
wait_WOC(iobase);
writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
ret = netwave_set_scramble(dev, NULL, &(wrq->u), key);
}
break;
case SIOCGIWMODE:
/* Mode of operation */
if(domain & 0x100)
wrq->u.mode = IW_MODE_INFRA;
else
wrq->u.mode = IW_MODE_ADHOC;
ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL);
break;
#else /* WIRELESS_EXT > 8 */
case SIOCGIWENCODE:
/* Get scramble key */
wrq->u.encoding.code = scramble_key;
wrq->u.encoding.method = 1;
ret = netwave_get_scramble(dev, NULL, &(wrq->u),
(char *) &wrq->u.encoding.code);
break;
case SIOCSIWENCODE:
/* Set scramble key */
scramble_key = wrq->u.encoding.code;
wait_WOC(iobase);
writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
ret = netwave_set_scramble(dev, NULL, &(wrq->u),
(char *) &wrq->u.encoding.code);
break;
#endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range;
/* Set the length (very important for backward compatibility) */
wrq->u.data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(&range, 0, sizeof(range));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range.we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9; /* Nothing for us in v10 and v11 */
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range.throughput = 450 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0x01FF;
range.num_channels = range.num_frequency = 0;
range.sensitivity = 0x3F;
range.max_qual.qual = 255;
range.max_qual.level = 255;
range.max_qual.noise = 0;
#if WIRELESS_EXT > 7
range.num_bitrates = 1;
range.bitrate[0] = 1000000; /* 1 Mb/s */
#endif /* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
range.encoding_size[0] = 2; /* 16 bits scrambling */
range.num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */
#endif /* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, &range,
ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range);
if (copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range)))
ret = -EFAULT;
}
......@@ -761,47 +998,36 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
case SIOCGIWPRIV:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) {
struct iw_priv_args priv[] =
{ /* cmd, set_args, get_args, name */
{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0,
sizeof(struct site_survey),
"getsitesurvey" },
};
/* Set the number of ioctl available */
wrq->u.data.length = 1;
wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]);
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv)))
if(copy_to_user(wrq->u.data.pointer,
(u_char *) netwave_private_args,
sizeof(netwave_private_args)))
ret = -EFAULT;
}
break;
case SIOCGIPSNAP:
if(wrq->u.data.pointer != (caddr_t) 0) {
/* Take snapshot of environment */
netwave_snapshot( priv, ramBase, iobase);
wrq->u.data.length = priv->nss.length;
char buffer[sizeof( struct site_survey)];
ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer);
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer,
(u_char *) &priv->nss,
buffer,
sizeof( struct site_survey)))
{
printk(KERN_DEBUG "Bad buffer!\n");
break;
}
priv->lastExec = jiffies;
}
break;
#endif
#endif /* WIRELESS_EXT <= 12 */
#endif /* WIRELESS_EXT */
default:
ret = -EOPNOTSUPP;
}
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return ret;
}
......
......@@ -1786,45 +1786,41 @@ static inline void wl_his_gather(device * dev, u8 * stats)
/*------------------------------------------------------------------*/
/*
* Perform ioctl for configuration and information.
* It is here that the wireless extensions are treated (iwconfig).
* Wireless Handler : get protocol name
*/
static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */
struct ifreq *rq, /* data passed */
int cmd)
{ /* ioctl number */
static int wavelan_get_name(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
strcpy(wrqu->name, "WaveLAN");
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set NWID
*/
static int wavelan_set_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iwreq *wrq = (struct iwreq *) rq;
psa_t psa;
mm_t m;
unsigned long flags;
int ret = 0;
int err = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
cmd);
#endif
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Look what is the request */
switch (cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
strcpy(wrq->u.name, "WaveLAN");
break;
case SIOCSIWNWID:
/* Set NWID in WaveLAN. */
if (!wrq->u.nwid.disabled) {
if (!wrqu->nwid.disabled) {
/* Set NWID in psa */
psa.psa_nwid[0] =
(wrq->u.nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
psa.psa_nwid_select = 0x01;
psa_write(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa,
......@@ -1853,29 +1849,93 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr);
break;
case SIOCGIWNWID:
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get NWID
*/
static int wavelan_get_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Read the NWID. */
psa_read(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
wrq->u.nwid.value =
(psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.disabled = !(psa.psa_nwid_select);
wrq->u.nwid.fixed = 1; /* Superfluous */
break;
wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrqu->nwid.disabled = !(psa.psa_nwid_select);
wrqu->nwid.fixed = 1; /* Superfluous */
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set frequency
*/
static int wavelan_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
case SIOCSIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
ret = wv_set_frequency(ioaddr, &(wrqu->freq));
else
ret = -EOPNOTSUPP;
break;
case SIOCGIWFREQ:
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get frequency
*/
static int wavelan_get_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
* Does it work for everybody, especially old cards? */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
......@@ -1884,27 +1944,48 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* Ask the EEPROM to read the frequency from the first area. */
fee_read(ioaddr, 0x00, &freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1;
wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrqu->freq.e = 1;
} else {
psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_subband - (char *) &psa,
(unsigned char *) &psa.psa_subband, 1);
if (psa.psa_subband <= 4) {
wrq->u.freq.m =
fixed_bands[psa.psa_subband];
wrq->u.freq.e = (psa.psa_subband != 0);
wrqu->freq.m = fixed_bands[psa.psa_subband];
wrqu->freq.e = (psa.psa_subband != 0);
} else
ret = -EOPNOTSUPP;
}
break;
case SIOCSIWSENS:
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set level threshold
*/
static int wavelan_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Set the level threshold. */
/* We should complain loudly if wrq->u.sens.fixed = 0, because we
/* We should complain loudly if wrqu->sens.fixed = 0, because we
* can't set auto mode... */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
......@@ -1912,44 +1993,80 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set),
psa.psa_thr_pre_set);
break;
case SIOCGIWSENS:
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get level threshold
*/
static int wavelan_get_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Read the level threshold. */
psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1;
break;
wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
wrqu->sens.fixed = 1;
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set encryption key
*/
static int wavelan_set_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
psa_t psa;
int ret = 0;
case SIOCSIWENCODE:
/* Set encryption key */
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check if capable of encryption */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP;
break;
}
/* Basic checking... */
if (wrq->u.encoding.pointer != (caddr_t) 0) {
/* Check the size of the key */
if (wrq->u.encoding.length != 8) {
if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
ret = -EINVAL;
break;
}
if(!ret) {
/* Basic checking... */
if (wrqu->encoding.length == 8) {
/* Copy the key in the driver */
wv_splx(lp, &flags);
err = copy_from_user(psa.psa_encryption_key,
wrq->u.encoding.pointer,
wrq->u.encoding.length);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
memcpy(psa.psa_encryption_key, extra,
wrqu->encoding.length);
psa.psa_encryption_select = 1;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select -
(char *) &psa,
......@@ -1963,7 +2080,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
psa_encryption_key, 8);
}
if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */
/* disable encryption */
if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
psa.psa_encryption_select = 0;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select -
......@@ -1975,30 +2093,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr);
break;
case SIOCGIWENCODE:
/* Read the encryption key */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP;
break;
}
/* only super-user can see encryption key */
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
/* Basic checking... */
if (wrq->u.encoding.pointer != (caddr_t) 0) {
/* Verify the user buffer */
ret =
verify_area(VERIFY_WRITE,
wrq->u.encoding.pointer, 8);
if (ret)
break;
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get encryption key
*/
static int wavelan_get_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check if encryption is available */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP;
} else {
/* Read the encryption key */
psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select -
(char *) &psa,
......@@ -2007,168 +2132,126 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* encryption is enabled ? */
if (psa.psa_encryption_select)
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
wrqu->encoding.flags = IW_ENCODE_ENABLED;
else
wrq->u.encoding.flags = IW_ENCODE_DISABLED;
wrq->u.encoding.flags |= mmc_encr(ioaddr);
wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrqu->encoding.flags |= mmc_encr(ioaddr);
/* Copy the key to the user buffer */
wrq->u.encoding.length = 8;
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.encoding.pointer,
psa.psa_encryption_key, 8))
ret = -EFAULT;
wv_splhi(lp, &flags);
wrqu->encoding.length = 8;
memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
}
break;
case SIOCGIWRANGE:
/* basic checking */
if (wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range;
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get range info
*/
static int wavelan_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
int ret = 0;
/* Set the length (very important for backward
* compatibility) */
wrq->u.data.length = sizeof(struct iw_range);
/* Set the length (very important for backward compatibility) */
wrqu->data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know
* about to zero */
memset(&range, 0, sizeof(range));
/* Set all the info we don't care or don't know about to zero */
memset(range, 0, sizeof(struct iw_range));
/* Set the Wireless Extension versions */
range.we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9;
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9;
/* Set information in the range struct. */
range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0xFFFF;
range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
range->min_nwid = 0x0000;
range->max_nwid = 0xFFFF;
range->sensitivity = 0x3F;
range->max_qual.qual = MMR_SGNL_QUAL;
range->max_qual.level = MMR_SIGNAL_LVL;
range->max_qual.noise = MMR_SILENCE_LVL;
range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */
range->avg_qual.level = 30;
range->avg_qual.noise = 8;
range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
range.num_channels = 10;
range.num_frequency =
wv_frequency_list(ioaddr, range.freq,
range->num_channels = 10;
range->num_frequency = wv_frequency_list(ioaddr, range->freq,
IW_MAX_FREQUENCIES);
} else
range.num_channels = range.num_frequency =
0;
range.sensitivity = 0x3F;
range.max_qual.qual = MMR_SGNL_QUAL;
range.max_qual.level = MMR_SIGNAL_LVL;
range.max_qual.noise = MMR_SILENCE_LVL;
range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */
range.avg_qual.level = 30;
range.avg_qual.noise = 8;
range.num_bitrates = 1;
range.bitrate[0] = 2000000; /* 2 Mb/s */
range->num_channels = range->num_frequency = 0;
/* Encryption supported ? */
if (mmc_encr(ioaddr)) {
range.encoding_size[0] = 8; /* DES = 64 bits key */
range.num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */
range->encoding_size[0] = 8; /* DES = 64 bits key */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
} else {
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
range->num_encoding_sizes = 0;
range->max_encoding_tokens = 0;
}
/* Copy structure to the user buffer. */
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.data.pointer,
&range,
sizeof(struct iw_range)))
ret = -EFAULT;
wv_splhi(lp, &flags);
}
break;
case SIOCGIWPRIV:
/* Basic checking */
if (wrq->u.data.pointer != (caddr_t) 0) {
struct iw_priv_args priv[] = {
/* { cmd,
set_args,
get_args,
name } */
{ SIOCSIPQTHR,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
0,
"setqualthr" },
{ SIOCGIPQTHR,
0,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
"getqualthr" },
{ SIOCSIPHISTO,
IW_PRIV_TYPE_BYTE | 16,
0,
"sethisto" },
{ SIOCGIPHISTO,
0,
IW_PRIV_TYPE_INT | 16,
"gethisto" },
};
/* Set the number of available ioctls. */
wrq->u.data.length = 4;
/* Copy structure to the user buffer. */
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.data.pointer,
(u8 *) priv,
sizeof(priv)))
ret = -EFAULT;
wv_splhi(lp, &flags);
}
break;
return ret;
}
#ifdef WIRELESS_SPY
case SIOCSIWSPY:
/* Set the spy list */
/* Check the number of addresses. */
if (wrq->u.data.length > IW_MAX_SPY) {
ret = -E2BIG;
break;
}
lp->spy_number = wrq->u.data.length;
/* Are there are addresses to copy? */
if (lp->spy_number > 0) {
struct sockaddr address[IW_MAX_SPY];
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set spy list
*/
static int wavelan_set_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i;
int ret = 0;
/* Copy addresses to the driver. */
wv_splx(lp, &flags);
err = copy_from_user(address,
wrq->u.data.pointer,
sizeof(struct sockaddr)
* lp->spy_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
/* Disable spy while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp->spy_number = 0;
/* Are there are addresses to copy? */
if (wrqu->data.length > 0) {
/* Copy addresses to the lp structure. */
for (i = 0; i < lp->spy_number; i++) {
memcpy(lp->spy_address[i],
address[i].sa_data,
for (i = 0; i < wrqu->data.length; i++) {
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
}
/* Reset structure. */
memset(lp->spy_stat, 0x00,
sizeof(iw_qual) * IW_MAX_SPY);
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG
"SetSpy: set of new addresses is: \n");
for (i = 0; i < wrq->u.data.length; i++)
for (i = 0; i < wrqu->data.length; i++)
printk(KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
......@@ -2180,20 +2263,28 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
#endif /* DEBUG_IOCTL_INFO */
}
break;
case SIOCGIWSPY:
/* Get the spy list and spy stats. */
/* Now we can set the number of addresses */
lp->spy_number = wrqu->data.length;
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
return ret;
}
/* Does the user want to have the addresses back? */
if ((lp->spy_number > 0)
&& (wrq->u.data.pointer != (caddr_t) 0)) {
struct sockaddr address[IW_MAX_SPY];
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get spy list
*/
static int wavelan_get_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i;
/* Set the number of addresses */
wrqu->data.length = lp->spy_number;
/* Copy addresses from the lp structure. */
for (i = 0; i < lp->spy_number; i++) {
memcpy(address[i].sa_data,
......@@ -2201,42 +2292,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
WAVELAN_ADDR_SIZE);
address[i].sa_family = AF_UNIX;
}
/* Copy addresses to the user buffer. */
wv_splx(lp, &flags);
err = copy_to_user(wrq->u.data.pointer,
address,
sizeof(struct sockaddr)
* lp->spy_number);
/* Copy stats to the user buffer (just after). */
err |= copy_to_user(wrq->u.data.pointer
+ (sizeof(struct sockaddr)
* lp->spy_number),
lp->spy_stat,
sizeof(iw_qual) * lp->spy_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
if(lp->spy_number > 0)
memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
/* Reset updated flags. */
for (i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
}
/* if(pointer != NULL) */
break;
return(0);
}
#endif /* WIRELESS_SPY */
/* ------------------ PRIVATE IOCTL ------------------ */
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set quality threshold
*/
static int wavelan_set_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
case SIOCSIPQTHR:
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
psa.psa_quality_thr = *(extra) & 0x0F;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
......@@ -2244,81 +2330,193 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
psa.psa_quality_thr);
break;
case SIOCGIPQTHR:
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static int wavelan_get_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
break;
*(extra) = psa.psa_quality_thr & 0x0F;
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return 0;
}
#ifdef HISTOGRAM
case SIOCSIPHISTO:
/* Verify that the user is root. */
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set histogram
*/
static int wavelan_set_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Check the number of intervals. */
if (wrq->u.data.length > 16) {
ret = -E2BIG;
break;
if (wrqu->data.length > 16) {
return(-E2BIG);
}
lp->his_number = wrq->u.data.length;
/* Are there addresses to copy? */
if (lp->his_number > 0) {
/* Disable histo while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp->his_number = 0;
/* Are there ranges to copy? */
if (wrqu->data.length > 0) {
/* Copy interval ranges to the driver */
wv_splx(lp, &flags);
err = copy_from_user(lp->his_range,
wrq->u.data.pointer,
sizeof(char) * lp->his_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
memcpy(lp->his_range, extra, wrqu->data.length);
{
int i;
printk(KERN_DEBUG "Histo :");
for(i = 0; i < wrqu->data.length; i++)
printk(" %d", lp->his_range[i]);
printk("\n");
}
/* Reset structure. */
/* Reset result structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
}
break;
case SIOCGIPHISTO:
/* Now we can set the number of ranges */
lp->his_number = wrqu->data.length;
return(0);
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get histogram
*/
static int wavelan_get_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Set the number of intervals. */
wrq->u.data.length = lp->his_number;
wrqu->data.length = lp->his_number;
/* Give back the distribution statistics */
if ((lp->his_number > 0)
&& (wrq->u.data.pointer != (caddr_t) 0)) {
/* Copy data to the user buffer. */
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.data.pointer,
lp->his_sum,
sizeof(long) * lp->his_number);
ret = -EFAULT;
wv_splhi(lp, &flags);
if(lp->his_number > 0)
memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number);
} /* if(pointer != NULL) */
break;
return(0);
}
#endif /* HISTOGRAM */
/* ------------------- OTHER IOCTL ------------------- */
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
default:
ret = -EOPNOTSUPP;
} /* switch (cmd) */
static const iw_handler wavelan_handler[] =
{
NULL, /* SIOCSIWNAME */
wavelan_get_name, /* SIOCGIWNAME */
wavelan_set_nwid, /* SIOCSIWNWID */
wavelan_get_nwid, /* SIOCGIWNWID */
wavelan_set_freq, /* SIOCSIWFREQ */
wavelan_get_freq, /* SIOCGIWFREQ */
NULL, /* SIOCSIWMODE */
NULL, /* SIOCGIWMODE */
wavelan_set_sens, /* SIOCSIWSENS */
wavelan_get_sens, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
wavelan_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
#ifdef WIRELESS_SPY
wavelan_set_spy, /* SIOCSIWSPY */
wavelan_get_spy, /* SIOCGIWSPY */
#else /* WIRELESS_SPY */
NULL, /* SIOCSIWSPY */
NULL, /* SIOCGIWSPY */
#endif /* WIRELESS_SPY */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWAP */
NULL, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWESSID */
NULL, /* SIOCGIWESSID */
NULL, /* SIOCSIWNICKN */
NULL, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWRATE */
NULL, /* SIOCGIWRATE */
NULL, /* SIOCSIWRTS */
NULL, /* SIOCGIWRTS */
NULL, /* SIOCSIWFRAG */
NULL, /* SIOCGIWFRAG */
NULL, /* SIOCSIWTXPOW */
NULL, /* SIOCGIWTXPOW */
NULL, /* SIOCSIWRETRY */
NULL, /* SIOCGIWRETRY */
/* Bummer ! Why those are only at the end ??? */
wavelan_set_encode, /* SIOCSIWENCODE */
wavelan_get_encode, /* SIOCGIWENCODE */
};
static const iw_handler wavelan_private_handler[] =
{
wavelan_set_qthr, /* SIOCIWFIRSTPRIV */
wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */
#ifdef HISTOGRAM
wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */
wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */
#endif /* HISTOGRAM */
};
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
static const struct iw_priv_args wavelan_private_args[] = {
/*{ cmd, set_args, get_args, name } */
{ SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
{ SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
{ SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
};
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif
return ret;
}
static const struct iw_handler_def wavelan_handler_def =
{
num_standard: sizeof(wavelan_handler)/sizeof(iw_handler),
num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler),
num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
standard: (iw_handler *) wavelan_handler,
private: (iw_handler *) wavelan_private_handler,
private_args: (struct iw_priv_args *) wavelan_private_args,
};
/*------------------------------------------------------------------*/
/*
......@@ -4069,8 +4267,8 @@ static int __init wavelan_config(device * dev)
#endif /* SET_MAC_ADDRESS */
#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->do_ioctl = wavelan_ioctl;
dev->get_wireless_stats = wavelan_get_wireless_stats;
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
#endif
dev->mtu = WAVELAN_MTU;
......
......@@ -345,6 +345,12 @@
* - Fix spinlock stupid bugs that I left in. The driver is now SMP
* compliant and doesn't lockup at startup.
*
* Changes made for release in 2.5.2 :
* ---------------------------------
* - Use new driver API for Wireless Extensions :
* o got rid of wavelan_ioctl()
* o use a bunch of iw_handler instead
*
* Wishes & dreams:
* ----------------
* - roaming (see Pcmcia driver)
......@@ -379,6 +385,7 @@
#include <linux/init.h>
#include <linux/wireless.h> /* Wireless extensions */
#include <net/iw_handler.h> /* Wireless handlers */
/* WaveLAN declarations */
#include "i82586.h"
......@@ -436,7 +443,7 @@
/************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW
static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n";
static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n";
#endif
/* Watchdog temporisation */
......@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/
#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */
#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */
#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2 /* Set level threshold */
#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3 /* Get level threshold */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */
/****************************** TYPES ******************************/
......
......@@ -1884,331 +1884,1149 @@ wl_his_gather(device * dev,
/*------------------------------------------------------------------*/
/*
* Perform ioctl : config & info stuff
* This is here that are treated the wireless extensions (iwconfig)
* Wireless Handler : get protocol name
*/
static int
wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
struct ifreq * rq, /* Data passed */
int cmd) /* Ioctl number */
static int wavelan_get_name(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
strcpy(wrqu->name, "WaveLAN");
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set NWID
*/
static int wavelan_set_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local * lp = (net_local *)dev->priv; /* lp is not unused */
struct iwreq * wrq = (struct iwreq *) rq;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
mm_t m;
unsigned long flags;
int ret = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#endif
/* Disable interrupts & save flags */
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Look what is the request */
switch(cmd)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
strcpy(wrq->u.name, "Wavelan");
break;
case SIOCSIWNWID:
/* Set NWID in wavelan */
/* Set NWID in WaveLAN. */
#if WIRELESS_EXT > 8
if(!wrq->u.nwid.disabled)
{
if (!wrqu->nwid.disabled) {
/* Set NWID in psa */
psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
#else /* WIRELESS_EXT > 8 */
if(wrq->u.nwid.on)
{
if(wrq->u.nwid.on) {
/* Set NWID in psa */
psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
#endif /* WIRELESS_EXT > 8 */
psa.psa_nwid_select = 0x01;
psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
psa_write(dev,
(char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
/* Set NWID in mmc */
/* Set NWID in mmc. */
m.w.mmw_netw_id_l = psa.psa_nwid[1];
m.w.mmw_netw_id_h = psa.psa_nwid[0];
mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m,
(unsigned char *)&m.w.mmw_netw_id_l, 2);
mmc_write(base,
(char *) &m.w.mmw_netw_id_l -
(char *) &m,
(unsigned char *) &m.w.mmw_netw_id_l, 2);
mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
}
else
{
/* Disable nwid in the psa */
} else {
/* Disable NWID in the psa. */
psa.psa_nwid_select = 0x00;
psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
(unsigned char *)&psa.psa_nwid_select, 1);
psa_write(dev,
(char *) &psa.psa_nwid_select -
(char *) &psa,
(unsigned char *) &psa.psa_nwid_select,
1);
/* Disable nwid in the mmc (no filtering) */
mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
/* Disable NWID in the mmc (no filtering). */
mmc_out(base, mmwoff(0, mmw_loopt_sel),
MMW_LOOPT_SEL_DIS_NWID);
}
/* update the Wavelan checksum */
update_psa_checksum(dev);
break;
case SIOCGIWNWID:
/* Read the NWID */
psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get NWID
*/
static int wavelan_get_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Read the NWID. */
psa_read(dev,
(char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
#if WIRELESS_EXT > 8
wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.disabled = !(psa.psa_nwid_select);
wrq->u.nwid.fixed = 1; /* Superfluous */
wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrqu->nwid.disabled = !(psa.psa_nwid_select);
wrqu->nwid.fixed = 1; /* Superfluous */
#else /* WIRELESS_EXT > 8 */
wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.on = psa.psa_nwid_select;
#endif /* WIRELESS_EXT > 8 */
break;
case SIOCSIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set frequency
*/
static int wavelan_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(base, &(wrq->u.freq));
ret = wv_set_frequency(base, &(wrqu->freq));
else
ret = -EOPNOTSUPP;
break;
case SIOCGIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
* (does it work for everybody ? - especially old cards...) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get frequency
*/
static int wavelan_get_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
* Does it work for everybody, especially old cards? */
if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
unsigned short freq;
/* Ask the EEprom to read the frequency from the first area */
fee_read(base, 0x00 /* 1st area - frequency... */,
&freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1;
/* Ask the EEPROM to read the frequency from the first area. */
fee_read(base, 0x00, &freq, 1);
wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrqu->freq.e = 1;
} else {
psa_read(dev,
(char *) &psa.psa_subband - (char *) &psa,
(unsigned char *) &psa.psa_subband, 1);
if (psa.psa_subband <= 4) {
wrqu->freq.m = fixed_bands[psa.psa_subband];
wrqu->freq.e = (psa.psa_subband != 0);
} else
ret = -EOPNOTSUPP;
}
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set level threshold
*/
static int wavelan_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Set the level threshold. */
#if WIRELESS_EXT > 7
/* We should complain loudly if wrqu->sens.fixed = 0, because we
* can't set auto mode... */
psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
#else /* WIRELESS_EXT > 7 */
psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
#endif /* WIRELESS_EXT > 7 */
psa_write(dev,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_thr_pre_set),
psa.psa_thr_pre_set);
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get level threshold
*/
static int wavelan_get_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Read the level threshold. */
psa_read(dev,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
#if WIRELESS_EXT > 7
wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
wrqu->sens.fixed = 1;
#else /* WIRELESS_EXT > 7 */
wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
#endif /* WIRELESS_EXT > 7 */
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
#if WIRELESS_EXT > 8
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set encryption key
*/
static int wavelan_set_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
psa_t psa;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check if capable of encryption */
if (!mmc_encr(base)) {
ret = -EOPNOTSUPP;
}
/* Check the size of the key */
if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
ret = -EINVAL;
}
if(!ret) {
/* Basic checking... */
if (wrqu->encoding.length == 8) {
/* Copy the key in the driver */
memcpy(psa.psa_encryption_key, extra,
wrqu->encoding.length);
psa.psa_encryption_select = 1;
psa_write(dev,
(char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 8 + 1);
mmc_out(base, mmwoff(0, mmw_encr_enable),
MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
mmc_write(base, mmwoff(0, mmw_encr_key),
(unsigned char *) &psa.
psa_encryption_key, 8);
}
/* disable encryption */
if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
psa.psa_encryption_select = 0;
psa_write(dev,
(char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 1);
mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
}
/* update the Wavelan checksum */
update_psa_checksum(dev);
}
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get encryption key
*/
static int wavelan_get_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check if encryption is available */
if (!mmc_encr(base)) {
ret = -EOPNOTSUPP;
} else {
/* Read the encryption key */
psa_read(dev,
(char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 1 + 8);
/* encryption is enabled ? */
if (psa.psa_encryption_select)
wrqu->encoding.flags = IW_ENCODE_ENABLED;
else
{
psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
(unsigned char *)&psa.psa_subband, 1);
wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrqu->encoding.flags |= mmc_encr(base);
/* Copy the key to the user buffer */
wrqu->encoding.length = 8;
memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
}
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
#endif /* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set ESSID (domain)
*/
static int wavelan_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check if disable */
if(wrqu->data.flags == 0)
lp->filter_domains = 0;
else {
char essid[IW_ESSID_MAX_SIZE + 1];
char * endp;
/* Terminate the string */
memcpy(essid, extra, wrqu->data.length);
essid[IW_ESSID_MAX_SIZE] = '\0';
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
#endif /* DEBUG_IOCTL_INFO */
/* Convert to a number (note : Wavelan specific) */
lp->domain_id = simple_strtoul(essid, &endp, 16);
/* Has it worked ? */
if(endp > essid)
lp->filter_domains = 1;
else {
lp->filter_domains = 0;
ret = -EINVAL;
}
}
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get ESSID (domain)
*/
static int wavelan_get_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Is the domain ID active ? */
wrqu->data.flags = lp->filter_domains;
/* Copy Domain ID into a string (Wavelan specific) */
/* Sound crazy, be we can't have a snprintf in the kernel !!! */
sprintf(extra, "%lX", lp->domain_id);
extra[IW_ESSID_MAX_SIZE] = '\0';
/* Set the length */
wrqu->data.length = strlen(extra) + 1;
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set AP address
*/
static int wavelan_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
wrqu->ap_addr.sa_data[0],
wrqu->ap_addr.sa_data[1],
wrqu->ap_addr.sa_data[2],
wrqu->ap_addr.sa_data[3],
wrqu->ap_addr.sa_data[4],
wrqu->ap_addr.sa_data[5]);
#endif /* DEBUG_IOCTL_INFO */
return -EOPNOTSUPP;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get AP address
*/
static int wavelan_get_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
/* Should get the real McCoy instead of own Ethernet address */
memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
return -EOPNOTSUPP;
}
#endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set mode
*/
static int wavelan_set_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check mode */
switch(wrqu->mode) {
case IW_MODE_ADHOC:
if(do_roaming) {
wv_roam_cleanup(dev);
do_roaming = 0;
}
break;
case IW_MODE_INFRA:
if(!do_roaming) {
wv_roam_init(dev);
do_roaming = 1;
}
break;
default:
ret = -EINVAL;
}
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get mode
*/
static int wavelan_get_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
if(do_roaming)
wrqu->mode = IW_MODE_INFRA;
else
wrqu->mode = IW_MODE_ADHOC;
return 0;
}
#endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get range info
*/
static int wavelan_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
int ret = 0;
/* Set the length (very important for backward compatibility) */
wrqu->data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(range, 0, sizeof(struct iw_range));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9;
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct. */
range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
range->min_nwid = 0x0000;
range->max_nwid = 0xFFFF;
range->sensitivity = 0x3F;
range->max_qual.qual = MMR_SGNL_QUAL;
range->max_qual.level = MMR_SIGNAL_LVL;
range->max_qual.noise = MMR_SILENCE_LVL;
#if WIRELESS_EXT > 11
range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */
range->avg_qual.level = 30;
range->avg_qual.noise = 8;
#endif /* WIRELESS_EXT > 11 */
#if WIRELESS_EXT > 7
range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */
#endif /* WIRELESS_EXT > 7 */
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
range->num_channels = 10;
range->num_frequency = wv_frequency_list(base, range->freq,
IW_MAX_FREQUENCIES);
} else
range->num_channels = range->num_frequency = 0;
#if WIRELESS_EXT > 8
/* Encryption supported ? */
if (mmc_encr(base)) {
range->encoding_size[0] = 8; /* DES = 64 bits key */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
} else {
range->num_encoding_sizes = 0;
range->max_encoding_tokens = 0;
}
#endif /* WIRELESS_EXT > 8 */
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
#ifdef WIRELESS_SPY
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set spy list
*/
static int wavelan_set_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i;
int ret = 0;
/* Disable spy while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp->spy_number = 0;
/* Are there are addresses to copy? */
if (wrqu->data.length > 0) {
/* Copy addresses to the lp structure. */
for (i = 0; i < wrqu->data.length; i++) {
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
}
/* Reset structure. */
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG
"SetSpy: set of new addresses is: \n");
for (i = 0; i < wrqu->data.length; i++)
printk(KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
lp->spy_address[i][1],
lp->spy_address[i][2],
lp->spy_address[i][3],
lp->spy_address[i][4],
lp->spy_address[i][5]);
#endif /* DEBUG_IOCTL_INFO */
}
/* Now we can set the number of addresses */
lp->spy_number = wrqu->data.length;
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get spy list
*/
static int wavelan_get_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i;
/* Set the number of addresses */
wrqu->data.length = lp->spy_number;
/* Copy addresses from the lp structure. */
for (i = 0; i < lp->spy_number; i++) {
memcpy(address[i].sa_data,
lp->spy_address[i],
WAVELAN_ADDR_SIZE);
address[i].sa_family = AF_UNIX;
}
/* Copy stats to the user buffer (just after). */
if(lp->spy_number > 0)
memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
/* Reset updated flags. */
for (i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
return(0);
}
#endif /* WIRELESS_SPY */
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set quality threshold
*/
static int wavelan_set_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
psa.psa_quality_thr = *(extra) & 0x0F;
psa_write(dev,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_quality_thr),
psa.psa_quality_thr);
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static int wavelan_get_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
psa_read(dev,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
*(extra) = psa.psa_quality_thr & 0x0F;
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return 0;
}
#ifdef WAVELAN_ROAMING
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set roaming
*/
static int wavelan_set_roam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Note : should check if user == root */
if(do_roaming && (*extra)==0)
wv_roam_cleanup(dev);
else if(do_roaming==0 && (*extra)!=0)
wv_roam_init(dev);
do_roaming = (*extra);
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static int wavelan_get_roam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
*(extra) = do_roaming;
return 0;
}
#endif /* WAVELAN_ROAMING */
#ifdef HISTOGRAM
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set histogram
*/
static int wavelan_set_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Check the number of intervals. */
if (wrqu->data.length > 16) {
return(-E2BIG);
}
/* Disable histo while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp->his_number = 0;
/* Are there ranges to copy? */
if (wrqu->data.length > 0) {
/* Copy interval ranges to the driver */
memcpy(lp->his_range, extra, wrqu->data.length);
{
int i;
printk(KERN_DEBUG "Histo :");
for(i = 0; i < wrqu->data.length; i++)
printk(" %d", lp->his_range[i]);
printk("\n");
}
/* Reset result structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
}
/* Now we can set the number of ranges */
lp->his_number = wrqu->data.length;
return(0);
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get histogram
*/
static int wavelan_get_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Set the number of intervals. */
wrqu->data.length = lp->his_number;
/* Give back the distribution statistics */
if(lp->his_number > 0)
memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number);
return(0);
}
#endif /* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
static const struct iw_priv_args wavelan_private_args[] = {
/*{ cmd, set_args, get_args, name } */
{ SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
{ SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
{ SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" },
{ SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
{ SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
};
#if WIRELESS_EXT > 12
static const iw_handler wavelan_handler[] =
{
NULL, /* SIOCSIWNAME */
wavelan_get_name, /* SIOCGIWNAME */
wavelan_set_nwid, /* SIOCSIWNWID */
wavelan_get_nwid, /* SIOCGIWNWID */
wavelan_set_freq, /* SIOCSIWFREQ */
wavelan_get_freq, /* SIOCGIWFREQ */
#ifdef WAVELAN_ROAMING
wavelan_set_mode, /* SIOCSIWMODE */
wavelan_get_mode, /* SIOCGIWMODE */
#else /* WAVELAN_ROAMING */
NULL, /* SIOCSIWMODE */
NULL, /* SIOCGIWMODE */
#endif /* WAVELAN_ROAMING */
wavelan_set_sens, /* SIOCSIWSENS */
wavelan_get_sens, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
wavelan_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
#ifdef WIRELESS_SPY
wavelan_set_spy, /* SIOCSIWSPY */
wavelan_get_spy, /* SIOCGIWSPY */
#else /* WIRELESS_SPY */
NULL, /* SIOCSIWSPY */
NULL, /* SIOCGIWSPY */
#endif /* WIRELESS_SPY */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
#ifdef WAVELAN_ROAMING_EXT
wavelan_set_wap, /* SIOCSIWAP */
wavelan_get_wap, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
wavelan_set_essid, /* SIOCSIWESSID */
wavelan_get_essid, /* SIOCGIWESSID */
#else /* WAVELAN_ROAMING_EXT */
NULL, /* SIOCSIWAP */
NULL, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWESSID */
NULL, /* SIOCGIWESSID */
#endif /* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8
NULL, /* SIOCSIWNICKN */
NULL, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWRATE */
NULL, /* SIOCGIWRATE */
NULL, /* SIOCSIWRTS */
NULL, /* SIOCGIWRTS */
NULL, /* SIOCSIWFRAG */
NULL, /* SIOCGIWFRAG */
NULL, /* SIOCSIWTXPOW */
NULL, /* SIOCGIWTXPOW */
NULL, /* SIOCSIWRETRY */
NULL, /* SIOCGIWRETRY */
wavelan_set_encode, /* SIOCSIWENCODE */
wavelan_get_encode, /* SIOCGIWENCODE */
#endif /* WIRELESS_EXT > 8 */
};
static const iw_handler wavelan_private_handler[] =
{
wavelan_set_qthr, /* SIOCIWFIRSTPRIV */
wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */
#ifdef WAVELAN_ROAMING
wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */
wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */
#else /* WAVELAN_ROAMING */
NULL, /* SIOCIWFIRSTPRIV + 2 */
NULL, /* SIOCIWFIRSTPRIV + 3 */
#endif /* WAVELAN_ROAMING */
#ifdef HISTOGRAM
wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */
wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */
#endif /* HISTOGRAM */
};
static const struct iw_handler_def wavelan_handler_def =
{
num_standard: sizeof(wavelan_handler)/sizeof(iw_handler),
num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler),
num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
standard: (iw_handler *) wavelan_handler,
private: (iw_handler *) wavelan_private_handler,
private_args: (struct iw_priv_args *) wavelan_private_args,
};
#else /* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/
/*
* Perform ioctl : config & info stuff
* This is here that are treated the wireless extensions (iwconfig)
*/
static int
wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
struct ifreq * rq, /* Data passed */
int cmd) /* Ioctl number */
{
struct iwreq * wrq = (struct iwreq *) rq;
int ret = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#endif
/* Look what is the request */
switch(cmd)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
wavelan_get_name(dev, NULL, &(wrq->u), NULL);
break;
case SIOCSIWNWID:
ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWNWID:
ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL);
break;
if(psa.psa_subband <= 4)
{
wrq->u.freq.m = fixed_bands[psa.psa_subband];
wrq->u.freq.e = (psa.psa_subband != 0);
}
else
ret = -EOPNOTSUPP;
}
case SIOCSIWFREQ:
ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWFREQ:
ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL);
break;
case SIOCSIWSENS:
/* Set the level threshold */
#if WIRELESS_EXT > 7
/* We should complain loudly if wrq->u.sens.fixed = 0, because we
* can't set auto mode... */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
#else /* WIRELESS_EXT > 7 */
psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
#endif /* WIRELESS_EXT > 7 */
psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *)&psa.psa_thr_pre_set, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWSENS:
/* Read the level threshold */
psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *)&psa.psa_thr_pre_set, 1);
#if WIRELESS_EXT > 7
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1;
#else /* WIRELESS_EXT > 7 */
wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
#endif /* WIRELESS_EXT > 7 */
ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL);
break;
#if WIRELESS_EXT > 8
case SIOCSIWENCODE:
/* Set encryption key */
if(!mmc_encr(base))
{
ret = -EOPNOTSUPP;
break;
}
/* Basic checking... */
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
/* Check the size of the key */
if(wrq->u.encoding.length != 8)
{
char keybuf[8];
if (wrq->u.encoding.pointer) {
/* We actually have a key to set */
if (wrq->u.encoding.length != 8) {
ret = -EINVAL;
break;
}
/* Copy the key in the driver */
if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
wrq->u.encoding.length))
{
if (copy_from_user(keybuf,
wrq->u.encoding.pointer,
wrq->u.encoding.length)) {
ret = -EFAULT;
break;
}
psa.psa_encryption_select = 1;
psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
(unsigned char *) &psa.psa_encryption_select, 8+1);
mmc_out(base, mmwoff(0, mmw_encr_enable),
MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
mmc_write(base, mmwoff(0, mmw_encr_key),
(unsigned char *) &psa.psa_encryption_key, 8);
} else if (wrq->u.encoding.length != 0) {
ret = -EINVAL;
break;
}
if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
{ /* disable encryption */
psa.psa_encryption_select = 0;
psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
(unsigned char *) &psa.psa_encryption_select, 1);
mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf);
}
/* update the Wavelan checksum */
update_psa_checksum(dev);
break;
case SIOCGIWENCODE:
/* Read the encryption key */
if(!mmc_encr(base))
{
ret = -EOPNOTSUPP;
break;
}
/* only super-user can see encryption key */
if(!capable(CAP_NET_ADMIN))
{
if (! capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
/* Basic checking... */
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
(unsigned char *) &psa.psa_encryption_select, 1+8);
/* encryption is enabled ? */
if(psa.psa_encryption_select)
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
else
wrq->u.encoding.flags = IW_ENCODE_DISABLED;
wrq->u.encoding.flags |= mmc_encr(base);
/* Copy the key to the user buffer */
wrq->u.encoding.length = 8;
if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
char keybuf[8];
ret = wavelan_get_encode(dev, NULL,
&(wrq->u),
keybuf);
if (wrq->u.encoding.pointer) {
if (copy_to_user(wrq->u.encoding.pointer,
keybuf,
wrq->u.encoding.length))
ret = -EFAULT;
}
}
break;
#endif /* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5
case SIOCSIWESSID:
/* Check if disable */
if(wrq->u.data.flags == 0)
lp->filter_domains = 0;
else
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
char essid[IW_ESSID_MAX_SIZE + 1];
char * endp;
/* Check the size of the string */
if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
{
char essidbuf[IW_ESSID_MAX_SIZE+1];
if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
break;
}
/* Copy the string in the driver */
if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
{
if (copy_from_user(essidbuf, wrq->u.essid.pointer,
wrq->u.essid.length)) {
ret = -EFAULT;
break;
}
essid[IW_ESSID_MAX_SIZE] = '\0';
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
#endif /* DEBUG_IOCTL_INFO */
/* Convert to a number (note : Wavelan specific) */
lp->domain_id = simple_strtoul(essid, &endp, 16);
/* Has it worked ? */
if(endp > essid)
lp->filter_domains = 1;
else
{
lp->filter_domains = 0;
ret = -EINVAL;
}
ret = wavelan_set_essid(dev, NULL,
&(wrq->u),
essidbuf);
}
break;
case SIOCGIWESSID:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
char essid[IW_ESSID_MAX_SIZE + 1];
/* Is the domain ID active ? */
wrq->u.data.flags = lp->filter_domains;
/* Copy Domain ID into a string (Wavelan specific) */
/* Sound crazy, be we can't have a snprintf in the kernel !!! */
sprintf(essid, "%lX", lp->domain_id);
essid[IW_ESSID_MAX_SIZE] = '\0';
/* Set the length */
wrq->u.data.length = strlen(essid) + 1;
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
char essidbuf[IW_ESSID_MAX_SIZE+1];
ret = wavelan_get_essid(dev, NULL,
&(wrq->u),
essidbuf);
if (wrq->u.essid.pointer)
if ( copy_to_user(wrq->u.essid.pointer,
essidbuf,
wrq->u.essid.length) )
ret = -EFAULT;
}
break;
case SIOCSIWAP:
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
wrq->u.ap_addr.sa_data[0],
wrq->u.ap_addr.sa_data[1],
wrq->u.ap_addr.sa_data[2],
wrq->u.ap_addr.sa_data[3],
wrq->u.ap_addr.sa_data[4],
wrq->u.ap_addr.sa_data[5]);
#endif /* DEBUG_IOCTL_INFO */
ret = -EOPNOTSUPP; /* Not supported yet */
ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWAP:
/* Should get the real McCoy instead of own Ethernet address */
memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
ret = -EOPNOTSUPP; /* Not supported yet */
ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */
......@@ -2216,103 +3034,22 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
#if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING
case SIOCSIWMODE:
switch(wrq->u.mode)
{
case IW_MODE_ADHOC:
if(do_roaming)
{
wv_roam_cleanup(dev);
do_roaming = 0;
}
break;
case IW_MODE_INFRA:
if(!do_roaming)
{
wv_roam_init(dev);
do_roaming = 1;
}
break;
default:
ret = -EINVAL;
}
ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWMODE:
if(do_roaming)
wrq->u.mode = IW_MODE_INFRA;
else
wrq->u.mode = IW_MODE_ADHOC;
ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_range range;
/* Set the length (very important for backward compatibility) */
wrq->u.data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(&range, 0, sizeof(range));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range.we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9; /* Nothing for us in v10 and v11 */
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0xFFFF;
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
range.num_channels = 10;
range.num_frequency = wv_frequency_list(base, range.freq,
IW_MAX_FREQUENCIES);
}
else
range.num_channels = range.num_frequency = 0;
range.sensitivity = 0x3F;
range.max_qual.qual = MMR_SGNL_QUAL;
range.max_qual.level = MMR_SIGNAL_LVL;
range.max_qual.noise = MMR_SILENCE_LVL;
#if WIRELESS_EXT > 11
range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */
range.avg_qual.level = 30;
range.avg_qual.noise = 8;
#endif /* WIRELESS_EXT > 11 */
#if WIRELESS_EXT > 7
range.num_bitrates = 1;
range.bitrate[0] = 2000000; /* 2 Mb/s */
#endif /* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
/* Encryption supported ? */
if(mmc_encr(base))
{
range.encoding_size[0] = 8; /* DES = 64 bits key */
range.num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */
}
else
{
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
}
#endif /* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, &range,
ret = wavelan_get_range(dev, NULL,
&(wrq->u),
(char *) &range);
if (copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range)))
ret = -EFAULT;
}
......@@ -2322,119 +3059,59 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_priv_args priv[] =
{ /* cmd, set_args, get_args, name */
{ SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
{ SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
{ SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
{ SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" },
{ SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
};
/* Set the number of ioctl available */
wrq->u.data.length = 6;
wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]);
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv)))
if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args,
sizeof(wavelan_private_args)))
ret = -EFAULT;
}
break;
#ifdef WIRELESS_SPY
case SIOCSIWSPY:
/* Set the spy list */
/* Check the number of addresses */
if(wrq->u.data.length > IW_MAX_SPY)
{
struct sockaddr address[IW_MAX_SPY];
/* Check the number of addresses */
if (wrq->u.data.length > IW_MAX_SPY) {
ret = -E2BIG;
break;
}
lp->spy_number = wrq->u.data.length;
/* If there is some addresses to copy */
if(lp->spy_number > 0)
{
struct sockaddr address[IW_MAX_SPY];
int i;
/* Copy addresses to the driver */
if(copy_from_user(address, wrq->u.data.pointer,
sizeof(struct sockaddr) * lp->spy_number))
{
/* Get the data in the driver */
if (wrq->u.data.pointer) {
if (copy_from_user((char *) address,
wrq->u.data.pointer,
sizeof(struct sockaddr) *
wrq->u.data.length)) {
ret = -EFAULT;
break;
}
/* Copy addresses to the lp structure */
for(i = 0; i < lp->spy_number; i++)
{
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
} else if (wrq->u.data.length != 0) {
ret = -EINVAL;
break;
}
/* Reset structure... */
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
for(i = 0; i < wrq->u.data.length; i++)
printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
lp->spy_address[i][0],
lp->spy_address[i][1],
lp->spy_address[i][2],
lp->spy_address[i][3],
lp->spy_address[i][4],
lp->spy_address[i][5]);
#endif /* DEBUG_IOCTL_INFO */
ret = wavelan_set_spy(dev, NULL, &(wrq->u),
(char *) address);
}
break;
case SIOCGIWSPY:
/* Get the spy list and spy stats */
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
/* If the user want to have the addresses back... */
if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{
struct sockaddr address[IW_MAX_SPY];
int i;
/* Copy addresses from the lp structure */
for(i = 0; i < lp->spy_number; i++)
{
memcpy(address[i].sa_data, lp->spy_address[i],
WAVELAN_ADDR_SIZE);
address[i].sa_family = ARPHRD_ETHER;
}
/* Copy addresses to the user buffer */
if(copy_to_user(wrq->u.data.pointer, address,
sizeof(struct sockaddr) * lp->spy_number))
{
char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
sizeof(struct iw_quality))];
ret = wavelan_get_spy(dev, NULL, &(wrq->u),
buffer);
if (wrq->u.data.pointer) {
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length *
(sizeof(struct sockaddr) +
sizeof(struct iw_quality)))
))
ret = -EFAULT;
break;
}
/* Copy stats to the user buffer (just after) */
if(copy_to_user(wrq->u.data.pointer +
(sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
{
ret = -EFAULT;
break;
}
/* Reset updated flags */
for(i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
} /* if(pointer != NULL) */
break;
#endif /* WIRELESS_SPY */
......@@ -2446,34 +3123,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EPERM;
break;
}
psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
(unsigned char *)&psa.psa_quality_thr, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIPQTHR:
psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
(unsigned char *)&psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL);
break;
#ifdef WAVELAN_ROAMING
case SIOCSIPROAM:
/* Note : should check if user == root */
if(do_roaming && (*wrq->u.name)==0)
wv_roam_cleanup(dev);
else if(do_roaming==0 && (*wrq->u.name)!=0)
wv_roam_init(dev);
do_roaming = (*wrq->u.name);
ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIPROAM:
*(wrq->u.name) = do_roaming;
ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WAVELAN_ROAMING */
......@@ -2484,44 +3148,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
{
ret = -EPERM;
}
{
char buffer[16];
/* Check the number of intervals */
if(wrq->u.data.length > 16)
{
ret = -E2BIG;
break;
}
lp->his_number = wrq->u.data.length;
/* If there is some addresses to copy */
if(lp->his_number > 0)
{
/* Copy interval ranges to the driver */
if(copy_from_user(lp->his_range, wrq->u.data.pointer,
sizeof(char) * lp->his_number))
{
/* Get the data in the driver */
if (wrq->u.data.pointer) {
if (copy_from_user(buffer,
wrq->u.data.pointer,
sizeof(struct sockaddr) *
wrq->u.data.length)) {
ret = -EFAULT;
break;
}
/* Reset structure... */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
} else if (wrq->u.data.length != 0) {
ret = -EINVAL;
break;
}
ret = wavelan_set_histo(dev, NULL, &(wrq->u),
buffer);
}
break;
case SIOCGIPHISTO:
/* Set the number of intervals */
wrq->u.data.length = lp->his_number;
/* Give back the distribution statistics */
if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{
/* Copy data to the user buffer */
if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
sizeof(long) * lp->his_number))
long buffer[16];
ret = wavelan_get_histo(dev, NULL, &(wrq->u),
(char *) buffer);
if (wrq->u.data.pointer) {
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length * sizeof(long))))
ret = -EFAULT;
} /* if(pointer != NULL) */
}
}
break;
#endif /* HISTOGRAM */
......@@ -2531,14 +3195,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EOPNOTSUPP;
}
/* ReEnable interrupts & restore flags */
wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif
return ret;
}
#endif /* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/
/*
......@@ -4530,7 +5192,11 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES;
#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
#else /* WIRELESS_EXT > 12 */
dev->do_ioctl = wavelan_ioctl; /* wireless extensions */
#endif /* WIRELESS_EXT > 12 */
dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif
......
......@@ -394,6 +394,12 @@
* o control first busy loop in wv_82593_cmd()
* o Extend spinlock protection in wv_hw_config()
*
* Changes made for release in 3.1.33 :
* ----------------------------------
* - Optional use new driver API for Wireless Extensions :
* o got rid of wavelan_ioctl()
* o use a bunch of iw_handler instead
*
* Wishes & dreams:
* ----------------
* - Cleanup and integrate the roaming code
......@@ -430,6 +436,9 @@
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Wireless extensions */
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif
/* Pcmcia headers that we need */
......@@ -498,7 +507,7 @@
/************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW
static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n";
#endif
/* Watchdog temporisation */
......@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/
#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */
#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */
/*************************** WaveLAN Roaming **************************/
#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */
......@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq;
typedef struct net_local net_local;
typedef struct timer_list timer_list;
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* Part of iw_handler prototype we need */
struct iw_request_info
{
__u16 cmd; /* Wireless Extension command */
__u16 flags; /* More to come ;-) */
};
#endif /* WIRELESS_EXT <= 12 */
/* Basic types */
typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment