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 @@ ...@@ -63,6 +63,9 @@
#ifdef CONFIG_NET_RADIO #ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> #include <linux/wireless.h>
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif #endif
#include <pcmcia/version.h> #include <pcmcia/version.h>
...@@ -269,6 +272,16 @@ static dev_link_t *dev_list; ...@@ -269,6 +272,16 @@ static dev_link_t *dev_list;
because they generally can't be allocated dynamically. 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 /* Wireless Extension Backward compatibility - Jean II
* If the new wireless device private ioctl range is not defined, * If the new wireless device private ioctl range is not defined,
* default to standard device private ioctl range */ * default to standard device private ioctl range */
...@@ -276,8 +289,11 @@ static dev_link_t *dev_list; ...@@ -276,8 +289,11 @@ static dev_link_t *dev_list;
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
#endif /* SIOCIWFIRSTPRIV */ #endif /* SIOCIWFIRSTPRIV */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV /* Site Survey Snapshot */ #else /* WIRELESS_EXT <= 12 */
/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/ static const struct iw_handler_def netwave_handler_def;
#endif /* WIRELESS_EXT <= 12 */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */
#define MAX_ESA 10 #define MAX_ESA 10
...@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void) ...@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void)
/* wireless extensions */ /* wireless extensions */
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
dev->get_wireless_stats = &netwave_get_wireless_stats; 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->do_ioctl = &netwave_ioctl;
dev->tx_timeout = &netwave_watchdog; dev->tx_timeout = &netwave_watchdog;
...@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void) ...@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void)
} }
} /* netwave_flush_stale_links */ } /* 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) * Function netwave_ioctl (dev, rq, cmd)
* *
...@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
struct ifreq *rq, /* Data passed */ struct ifreq *rq, /* Data passed */
int cmd) /* Ioctl number */ int cmd) /* Ioctl number */
{ {
unsigned long flags;
int ret = 0; int ret = 0;
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
ioaddr_t iobase = dev->base_addr; #if WIRELESS_EXT <= 12
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
struct iwreq *wrq = (struct iwreq *) rq; struct iwreq *wrq = (struct iwreq *) rq;
#endif
#endif #endif
DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); 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 */ /* Look what is the request */
switch(cmd) { switch(cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */ /* --------------- WIRELESS EXTENSIONS --------------- */
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
#if WIRELESS_EXT <= 12
case SIOCGIWNAME: case SIOCGIWNAME:
/* Get name */ netwave_get_name(dev, NULL, &(wrq->u), NULL);
strcpy(wrq->u.name, "Netwave");
break; break;
case SIOCSIWNWID: case SIOCSIWNWID:
/* Set domain */ ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL);
#if WIRELESS_EXT > 8 break;
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;
case SIOCGIWNWID: case SIOCGIWNWID:
/* Read domain*/ ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL);
#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 */
break; break;
#if WIRELESS_EXT > 8 /* Note : The API did change... */ #if WIRELESS_EXT > 8 /* Note : The API did change... */
case SIOCGIWENCODE: case SIOCGIWENCODE:
...@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
if(wrq->u.encoding.pointer != (caddr_t) 0) if(wrq->u.encoding.pointer != (caddr_t) 0)
{ {
char key[2]; char key[2];
key[1] = scramble_key & 0xff; ret = netwave_get_scramble(dev, NULL, &(wrq->u), key);
key[0] = (scramble_key>>8) & 0xff;
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
wrq->u.encoding.length = 2;
if(copy_to_user(wrq->u.encoding.pointer, key, 2)) if(copy_to_user(wrq->u.encoding.pointer, key, 2))
ret = -EFAULT; ret = -EFAULT;
} }
...@@ -681,127 +966,68 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -681,127 +966,68 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
scramble_key = (key[0] << 8) | key[1]; ret = netwave_set_scramble(dev, NULL, &(wrq->u), key);
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);
} }
break; break;
case SIOCGIWMODE: case SIOCGIWMODE:
/* Mode of operation */ /* Mode of operation */
if(domain & 0x100) ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL);
wrq->u.mode = IW_MODE_INFRA; break;
else
wrq->u.mode = IW_MODE_ADHOC;
break;
#else /* WIRELESS_EXT > 8 */ #else /* WIRELESS_EXT > 8 */
case SIOCGIWENCODE: case SIOCGIWENCODE:
/* Get scramble key */ /* Get scramble key */
wrq->u.encoding.code = scramble_key; ret = netwave_get_scramble(dev, NULL, &(wrq->u),
wrq->u.encoding.method = 1; (char *) &wrq->u.encoding.code);
break; break;
case SIOCSIWENCODE: case SIOCSIWENCODE:
/* Set scramble key */ /* Set scramble key */
scramble_key = wrq->u.encoding.code; ret = netwave_set_scramble(dev, NULL, &(wrq->u),
wait_WOC(iobase); (char *) &wrq->u.encoding.code);
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);
break; break;
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE: case SIOCGIWRANGE:
/* Basic checking... */ /* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) { if(wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range; struct iw_range range;
ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range);
/* Set the length (very important for backward compatibility) */ if (copy_to_user(wrq->u.data.pointer, &range,
wrq->u.data.length = sizeof(struct iw_range); sizeof(struct iw_range)))
ret = -EFAULT;
/* 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,
sizeof(struct iw_range)))
ret = -EFAULT;
} }
break; break;
case SIOCGIWPRIV: case SIOCGIWPRIV:
/* Basic checking... */ /* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) { 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 */ /* 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 */ /* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, if(copy_to_user(wrq->u.data.pointer,
sizeof(priv))) (u_char *) netwave_private_args,
sizeof(netwave_private_args)))
ret = -EFAULT; ret = -EFAULT;
} }
break; break;
case SIOCGIPSNAP: case SIOCGIPSNAP:
if(wrq->u.data.pointer != (caddr_t) 0) { if(wrq->u.data.pointer != (caddr_t) 0) {
/* Take snapshot of environment */ char buffer[sizeof( struct site_survey)];
netwave_snapshot( priv, ramBase, iobase); ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer);
wrq->u.data.length = priv->nss.length;
/* Copy structure to the user buffer */ /* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, if(copy_to_user(wrq->u.data.pointer,
(u_char *) &priv->nss, buffer,
sizeof( struct site_survey))) sizeof( struct site_survey)))
{ {
printk(KERN_DEBUG "Bad buffer!\n"); printk(KERN_DEBUG "Bad buffer!\n");
break; break;
} }
priv->lastExec = jiffies;
} }
break; break;
#endif #endif /* WIRELESS_EXT <= 12 */
#endif /* WIRELESS_EXT */
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return ret; return ret;
} }
......
...@@ -1786,170 +1786,287 @@ static inline void wl_his_gather(device * dev, u8 * stats) ...@@ -1786,170 +1786,287 @@ static inline void wl_his_gather(device * dev, u8 * stats)
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Perform ioctl for configuration and information. * Wireless Handler : get protocol name
* It is here that the wireless extensions are treated (iwconfig).
*/ */
static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ static int wavelan_get_name(struct net_device *dev,
struct ifreq *rq, /* data passed */ struct iw_request_info *info,
int cmd) union iwreq_data *wrqu,
{ /* ioctl number */ 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; unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iwreq *wrq = (struct iwreq *) rq;
psa_t psa; psa_t psa;
mm_t m; mm_t m;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
int err = 0;
#ifdef DEBUG_IOCTL_TRACE /* Disable interrupts and save flags. */
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, wv_splhi(lp, &flags);
cmd);
#endif /* Set NWID in WaveLAN. */
if (!wrqu->nwid.disabled) {
/* Set NWID in psa */
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,
(unsigned char *) psa.psa_nwid, 3);
/* 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(ioaddr,
(char *) &m.w.mmw_netw_id_l -
(char *) &m,
(unsigned char *) &m.w.mmw_netw_id_l, 2);
mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
} else {
/* Disable NWID in the psa. */
psa.psa_nwid_select = 0x00;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_nwid_select -
(char *) &psa,
(unsigned char *) &psa.psa_nwid_select,
1);
/* Disable NWID in the mmc (no filtering). */
mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel),
MMW_LOOPT_SEL_DIS_NWID);
}
/* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr);
/* 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. */ /* Disable interrupts and save flags. */
wv_splhi(lp, &flags); wv_splhi(lp, &flags);
/* Look what is the request */ /* Read the NWID. */
switch (cmd) { psa_read(ioaddr, lp->hacr,
/* --------------- WIRELESS EXTENSIONS --------------- */ (char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
case SIOCGIWNAME: wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
strcpy(wrq->u.name, "WaveLAN"); wrqu->nwid.disabled = !(psa.psa_nwid_select);
break; wrqu->nwid.fixed = 1; /* Superfluous */
case SIOCSIWNWID:
/* Set NWID in WaveLAN. */
if (!wrq->u.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_select = 0x01;
psa_write(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
/* 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(ioaddr,
(char *) &m.w.mmw_netw_id_l -
(char *) &m,
(unsigned char *) &m.w.mmw_netw_id_l, 2);
mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00);
} else {
/* Disable NWID in the psa. */
psa.psa_nwid_select = 0x00;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_nwid_select -
(char *) &psa,
(unsigned char *) &psa.psa_nwid_select,
1);
/* Disable NWID in the mmc (no filtering). */ /* Enable interrupts and restore flags. */
mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), wv_splx(lp, &flags);
MMW_LOOPT_SEL_DIS_NWID);
}
/* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr);
break;
case SIOCGIWNWID: return ret;
/* 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;
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));
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(ioaddr, 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(ioaddr, 0x00, &freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.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);
} else
ret = -EOPNOTSUPP;
}
break;
case SIOCSIWSENS: /*------------------------------------------------------------------*/
/* Set the level threshold. */ /*
/* We should complain loudly if wrq->u.sens.fixed = 0, because we * Wireless Handler : set frequency
* can't set auto mode... */ */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; static int wavelan_set_freq(struct net_device *dev,
psa_write(ioaddr, lp->hacr, struct iw_request_info *info,
(char *) &psa.psa_thr_pre_set - (char *) &psa, union iwreq_data *wrqu,
(unsigned char *) &psa.psa_thr_pre_set, 1); char *extra)
/* update the Wavelan checksum */ {
update_psa_checksum(dev, ioaddr, lp->hacr); unsigned long ioaddr = dev->base_addr;
mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa.psa_thr_pre_set); unsigned long flags;
break; int ret;
case SIOCGIWSENS: /* Disable interrupts and save flags. */
/* Read the level threshold. */ 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)))
ret = wv_set_frequency(ioaddr, &(wrqu->freq));
else
ret = -EOPNOTSUPP;
/* 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)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
unsigned short freq;
/* Ask the EEPROM to read the frequency from the first area. */
fee_read(ioaddr, 0x00, &freq, 1);
wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrqu->freq.e = 1;
} else {
psa_read(ioaddr, lp->hacr, psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa, (char *) &psa.psa_subband - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1); (unsigned char *) &psa.psa_subband, 1);
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1; if (psa.psa_subband <= 4) {
break; wrqu->freq.m = fixed_bands[psa.psa_subband];
wrqu->freq.e = (psa.psa_subband != 0);
case SIOCSIWENCODE: } else
/* Set encryption key */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; }
}
/* Basic checking... */ /* Enable interrupts and restore flags. */
if (wrq->u.encoding.pointer != (caddr_t) 0) { wv_splx(lp, &flags);
/* Check the size of the key */
if (wrq->u.encoding.length != 8) {
ret = -EINVAL;
break;
}
/* Copy the key in the driver */ return ret;
wv_splx(lp, &flags); }
err = copy_from_user(psa.psa_encryption_key,
wrq->u.encoding.pointer, /*------------------------------------------------------------------*/
wrq->u.encoding.length); /*
wv_splhi(lp, &flags); * Wireless Handler : set level threshold
if (err) { */
ret = -EFAULT; static int wavelan_set_sens(struct net_device *dev,
break; 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 wrqu->sens.fixed = 0, because we
* can't set auto mode... */
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);
/* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, 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)
{
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);
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;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Check if capable of encryption */
if (!mmc_encr(ioaddr)) {
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.psa_encryption_select = 1;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa.psa_encryption_select -
(char *) &psa, (char *) &psa,
...@@ -1963,7 +2080,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1963,7 +2080,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
psa_encryption_key, 8); 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.psa_encryption_select = 0;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa.psa_encryption_select -
...@@ -1975,350 +2093,430 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1975,350 +2093,430 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
} }
/* update the Wavelan checksum */ /* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr); update_psa_checksum(dev, ioaddr, lp->hacr);
break; }
/* 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)
{
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;
case SIOCGIWENCODE: /* 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 */ /* Read the encryption key */
if (!mmc_encr(ioaddr)) { psa_read(ioaddr, lp->hacr,
ret = -EOPNOTSUPP; (char *) &psa.psa_encryption_select -
break; (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
wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrqu->encoding.flags |= mmc_encr(ioaddr);
/* only super-user can see encryption key */ /* Copy the key to the user buffer */
if (!capable(CAP_NET_ADMIN)) { wrqu->encoding.length = 8;
ret = -EPERM; memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
break; }
}
/* Basic checking... */ /* Enable interrupts and restore flags. */
if (wrq->u.encoding.pointer != (caddr_t) 0) { wv_splx(lp, &flags);
/* Verify the user buffer */
ret =
verify_area(VERIFY_WRITE,
wrq->u.encoding.pointer, 8);
if (ret)
break;
psa_read(ioaddr, lp->hacr, return ret;
(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; * Wireless Handler : get range info
else */
wrq->u.encoding.flags = IW_ENCODE_DISABLED; static int wavelan_get_range(struct net_device *dev,
wrq->u.encoding.flags |= mmc_encr(ioaddr); struct iw_request_info *info,
union iwreq_data *wrqu,
/* Copy the key to the user buffer */ char *extra)
wrq->u.encoding.length = 8; {
wv_splx(lp, &flags); unsigned long ioaddr = dev->base_addr;
if (copy_to_user(wrq->u.encoding.pointer, net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa.psa_encryption_key, 8)) struct iw_range *range = (struct iw_range *) extra;
ret = -EFAULT; unsigned long flags;
wv_splhi(lp, &flags); int ret = 0;
}
break;
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));
/* Set the Wireless Extension versions */
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;
/* 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,
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 */
/* 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 */
} else {
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
}
/* Copy structure to the user buffer. */ /* Set the length (very important for backward compatibility) */
wv_splx(lp, &flags); wrqu->data.length = sizeof(struct iw_range);
if (copy_to_user(wrq->u.data.pointer,
&range, /* Set all the info we don't care or don't know about to zero */
sizeof(struct iw_range))) memset(range, 0, sizeof(struct iw_range));
ret = -EFAULT;
wv_splhi(lp, &flags); /* Set the Wireless Extension versions */
} range->we_version_compiled = WIRELESS_EXT;
break; range->we_version_source = 9;
case SIOCGIWPRIV: /* Set information in the range struct. */
/* Basic checking */ range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
if (wrq->u.data.pointer != (caddr_t) 0) { range->min_nwid = 0x0000;
struct iw_priv_args priv[] = { range->max_nwid = 0xFFFF;
/* { cmd,
set_args, range->sensitivity = 0x3F;
get_args, range->max_qual.qual = MMR_SGNL_QUAL;
name } */ range->max_qual.level = MMR_SIGNAL_LVL;
{ SIOCSIPQTHR, range->max_qual.noise = MMR_SILENCE_LVL;
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
0, /* Need to get better values for those two */
"setqualthr" }, range->avg_qual.level = 30;
{ SIOCGIPQTHR, range->avg_qual.noise = 8;
0,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, range->num_bitrates = 1;
"getqualthr" }, range->bitrate[0] = 2000000; /* 2 Mb/s */
{ SIOCSIPHISTO,
IW_PRIV_TYPE_BYTE | 16, /* Disable interrupts and save flags. */
0, wv_splhi(lp, &flags);
"sethisto" },
{ SIOCGIPHISTO, /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
0, if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
IW_PRIV_TYPE_INT | 16, (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
"gethisto" }, range->num_channels = 10;
}; range->num_frequency = wv_frequency_list(ioaddr, range->freq,
IW_MAX_FREQUENCIES);
/* Set the number of available ioctls. */ } else
wrq->u.data.length = 4; range->num_channels = range->num_frequency = 0;
/* Copy structure to the user buffer. */ /* Encryption supported ? */
wv_splx(lp, &flags); if (mmc_encr(ioaddr)) {
if (copy_to_user(wrq->u.data.pointer, range->encoding_size[0] = 8; /* DES = 64 bits key */
(u8 *) priv, range->num_encoding_sizes = 1;
sizeof(priv))) range->max_encoding_tokens = 1; /* Only one key possible */
ret = -EFAULT; } else {
wv_splhi(lp, &flags); range->num_encoding_sizes = 0;
} range->max_encoding_tokens = 0;
break; }
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return ret;
}
#ifdef WIRELESS_SPY #ifdef WIRELESS_SPY
case SIOCSIWSPY: /*------------------------------------------------------------------*/
/* Set the spy list */ /*
* 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;
/* Check the number of addresses. */ /* Disable spy while we copy the addresses.
if (wrq->u.data.length > IW_MAX_SPY) { * As we don't disable interrupts, we need to do this */
ret = -E2BIG; lp->spy_number = 0;
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];
int i;
/* 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;
}
/* Copy addresses to the lp structure. */ /* Are there are addresses to copy? */
for (i = 0; i < lp->spy_number; i++) { if (wrqu->data.length > 0) {
memcpy(lp->spy_address[i], /* Copy addresses to the lp structure. */
address[i].sa_data, for (i = 0; i < wrqu->data.length; i++) {
WAVELAN_ADDR_SIZE); memcpy(lp->spy_address[i], address[i].sa_data,
} WAVELAN_ADDR_SIZE);
}
/* Reset structure. */ /* Reset structure. */
memset(lp->spy_stat, 0x00, memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO #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 printk(KERN_DEBUG
"SetSpy: set of new addresses is: \n"); "%02X:%02X:%02X:%02X:%02X:%02X \n",
for (i = 0; i < wrq->u.data.length; i++) lp->spy_address[i][0],
printk(KERN_DEBUG lp->spy_address[i][1],
"%02X:%02X:%02X:%02X:%02X:%02X \n", lp->spy_address[i][2],
lp->spy_address[i][0], lp->spy_address[i][3],
lp->spy_address[i][1], lp->spy_address[i][4],
lp->spy_address[i][2], lp->spy_address[i][5]);
lp->spy_address[i][3], #endif /* DEBUG_IOCTL_INFO */
lp->spy_address[i][4], }
lp->spy_address[i][5]);
#endif /* DEBUG_IOCTL_INFO */
}
break; /* Now we can set the number of addresses */
lp->spy_number = wrqu->data.length;
case SIOCGIWSPY: return ret;
/* Get the spy list and spy stats. */ }
/* Set the number of addresses */ /*------------------------------------------------------------------*/
wrq->u.data.length = lp->spy_number; /*
* 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;
/* Does the user want to have the addresses back? */ /* Set the number of addresses */
if ((lp->spy_number > 0) wrqu->data.length = lp->spy_number;
&& (wrq->u.data.pointer != (caddr_t) 0)) {
struct sockaddr address[IW_MAX_SPY];
int i;
/* Copy addresses from the lp structure. */ /* Copy addresses from the lp structure. */
for (i = 0; i < lp->spy_number; i++) { for (i = 0; i < lp->spy_number; i++) {
memcpy(address[i].sa_data, memcpy(address[i].sa_data,
lp->spy_address[i], lp->spy_address[i],
WAVELAN_ADDR_SIZE); WAVELAN_ADDR_SIZE);
address[i].sa_family = AF_UNIX; 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);
/* Copy addresses to the user buffer. */ /* Reset updated flags. */
wv_splx(lp, &flags); for (i = 0; i < lp->spy_number; i++)
err = copy_to_user(wrq->u.data.pointer, lp->spy_stat[i].updated = 0x0;
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;
}
/* Reset updated flags. */ return(0);
for (i = 0; i < lp->spy_number; i++) }
lp->spy_stat[i].updated = 0x0; #endif /* WIRELESS_SPY */
}
/* if(pointer != NULL) */
break;
#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: /* Disable interrupts and save flags. */
if (!capable(CAP_NET_ADMIN)) { wv_splhi(lp, &flags);
ret = -EPERM;
break; psa.psa_quality_thr = *(extra) & 0x0F;
} psa_write(ioaddr, lp->hacr,
psa.psa_quality_thr = *(wrq->u.name) & 0x0F; (char *) &psa.psa_quality_thr - (char *) &psa,
psa_write(ioaddr, lp->hacr, (unsigned char *) &psa.psa_quality_thr, 1);
(char *) &psa.psa_quality_thr - (char *) &psa, /* update the Wavelan checksum */
(unsigned char *) &psa.psa_quality_thr, 1); update_psa_checksum(dev, ioaddr, lp->hacr);
/* update the Wavelan checksum */ mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
update_psa_checksum(dev, ioaddr, lp->hacr); psa.psa_quality_thr);
mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
psa.psa_quality_thr);
break;
case SIOCGIPQTHR: /* Enable interrupts and restore flags. */
psa_read(ioaddr, lp->hacr, wv_splx(lp, &flags);
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1); return 0;
*(wrq->u.name) = psa.psa_quality_thr & 0x0F; }
break;
/*------------------------------------------------------------------*/
/*
* 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);
*(extra) = psa.psa_quality_thr & 0x0F;
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
return 0;
}
#ifdef HISTOGRAM #ifdef HISTOGRAM
case SIOCSIPHISTO: /*------------------------------------------------------------------*/
/* Verify that the user is root. */ /*
if (!capable(CAP_NET_ADMIN)) { * Wireless Private Handler : set histogram
ret = -EPERM; */
break; 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. */ /* Check the number of intervals. */
if (wrq->u.data.length > 16) { if (wrqu->data.length > 16) {
ret = -E2BIG; return(-E2BIG);
break; }
}
lp->his_number = wrq->u.data.length;
/* Are there addresses to copy? */
if (lp->his_number > 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;
}
/* Reset structure. */ /* Disable histo while we copy the addresses.
memset(lp->his_sum, 0x00, sizeof(long) * 16); * 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");
} }
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. */
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(pointer != NULL) */
break;
#endif /* HISTOGRAM */
/* ------------------- OTHER IOCTL ------------------- */ /* Reset result structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
}
default: /* Now we can set the number of ranges */
ret = -EOPNOTSUPP; lp->his_number = wrqu->data.length;
} /* switch (cmd) */
/* Enable interrupts and restore flags. */ return(0);
wv_splx(lp, &flags); }
#ifdef DEBUG_IOCTL_TRACE /*------------------------------------------------------------------*/
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); /*
#endif * Wireless Private Handler : get histogram
return ret; */
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 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 */
};
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" },
};
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) ...@@ -4069,8 +4267,8 @@ static int __init wavelan_config(device * dev)
#endif /* SET_MAC_ADDRESS */ #endif /* SET_MAC_ADDRESS */
#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->do_ioctl = wavelan_ioctl;
dev->get_wireless_stats = wavelan_get_wireless_stats; dev->get_wireless_stats = wavelan_get_wireless_stats;
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
#endif #endif
dev->mtu = WAVELAN_MTU; dev->mtu = WAVELAN_MTU;
......
...@@ -345,6 +345,12 @@ ...@@ -345,6 +345,12 @@
* - Fix spinlock stupid bugs that I left in. The driver is now SMP * - Fix spinlock stupid bugs that I left in. The driver is now SMP
* compliant and doesn't lockup at startup. * 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: * Wishes & dreams:
* ---------------- * ----------------
* - roaming (see Pcmcia driver) * - roaming (see Pcmcia driver)
...@@ -379,6 +385,7 @@ ...@@ -379,6 +385,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/wireless.h> /* Wireless extensions */ #include <linux/wireless.h> /* Wireless extensions */
#include <net/iw_handler.h> /* Wireless handlers */
/* WaveLAN declarations */ /* WaveLAN declarations */
#include "i82586.h" #include "i82586.h"
...@@ -436,7 +443,7 @@ ...@@ -436,7 +443,7 @@
/************************ CONSTANTS & MACROS ************************/ /************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW #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 #endif
/* Watchdog temporisation */ /* Watchdog temporisation */
...@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/ ...@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/
#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */
#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get 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 SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */
/****************************** TYPES ******************************/ /****************************** TYPES ******************************/
......
...@@ -1882,6 +1882,1017 @@ wl_his_gather(device * dev, ...@@ -1882,6 +1882,1017 @@ wl_his_gather(device * dev,
} }
#endif /* HISTOGRAM */ #endif /* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get protocol name
*/
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 */
psa_t psa;
mm_t m;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
/* Set NWID in WaveLAN. */
#if WIRELESS_EXT > 8
if (!wrqu->nwid.disabled) {
/* Set NWID in psa */
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) {
/* 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);
/* 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_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
} 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);
/* 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);
/* 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
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 */
/* 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, &(wrqu->freq));
else
ret = -EOPNOTSUPP;
/* 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, &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
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 * Perform ioctl : config & info stuff
...@@ -1892,323 +2903,130 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -1892,323 +2903,130 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
struct ifreq * rq, /* Data passed */ struct ifreq * rq, /* Data passed */
int cmd) /* Ioctl number */ int cmd) /* Ioctl number */
{ {
ioaddr_t base = dev->base_addr;
net_local * lp = (net_local *)dev->priv; /* lp is not unused */
struct iwreq * wrq = (struct iwreq *) rq; struct iwreq * wrq = (struct iwreq *) rq;
psa_t psa;
mm_t m;
unsigned long flags;
int ret = 0; int ret = 0;
#ifdef DEBUG_IOCTL_TRACE #ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#endif #endif
/* Disable interrupts & save flags */
wv_splhi(lp, &flags);
/* Look what is the request */ /* Look what is the request */
switch(cmd) switch(cmd)
{ {
/* --------------- WIRELESS EXTENSIONS --------------- */ /* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME: case SIOCGIWNAME:
strcpy(wrq->u.name, "Wavelan"); wavelan_get_name(dev, NULL, &(wrq->u), NULL);
break; break;
case SIOCSIWNWID: case SIOCSIWNWID:
/* Set NWID in wavelan */ ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL);
#if WIRELESS_EXT > 8
if(!wrq->u.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;
#else /* WIRELESS_EXT > 8 */
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);
/* 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_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
}
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);
/* 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; break;
case SIOCGIWNWID: case SIOCGIWNWID:
/* Read the NWID */ ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL);
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 */
#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; break;
case SIOCSIWFREQ: case SIOCSIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL);
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));
else
ret = -EOPNOTSUPP;
break; break;
case SIOCGIWFREQ: case SIOCGIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL);
* (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;
}
else
{
psa_read(dev, (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);
}
else
ret = -EOPNOTSUPP;
}
break; break;
case SIOCSIWSENS: case SIOCSIWSENS:
/* Set the level threshold */ ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL);
#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);
break; break;
case SIOCGIWSENS: case SIOCGIWSENS:
/* Read the level threshold */ ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL);
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 */
break; break;
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
case SIOCSIWENCODE: case SIOCSIWENCODE:
/* Set encryption key */ {
if(!mmc_encr(base)) char keybuf[8];
{ if (wrq->u.encoding.pointer) {
ret = -EOPNOTSUPP; /* We actually have a key to set */
if (wrq->u.encoding.length != 8) {
ret = -EINVAL;
break;
}
if (copy_from_user(keybuf,
wrq->u.encoding.pointer,
wrq->u.encoding.length)) {
ret = -EFAULT;
break;
}
} else if (wrq->u.encoding.length != 0) {
ret = -EINVAL;
break; break;
} }
ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf);
/* Basic checking... */ }
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
/* Check the size of the key */
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))
{
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);
}
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);
}
/* update the Wavelan checksum */
update_psa_checksum(dev);
break; break;
case SIOCGIWENCODE: case SIOCGIWENCODE:
/* Read the encryption key */ if (! capable(CAP_NET_ADMIN)) {
if(!mmc_encr(base)) ret = -EPERM;
{ break;
ret = -EOPNOTSUPP; }
break; {
} char keybuf[8];
ret = wavelan_get_encode(dev, NULL,
/* only super-user can see encryption key */ &(wrq->u),
if(!capable(CAP_NET_ADMIN)) keybuf);
{ if (wrq->u.encoding.pointer) {
ret = -EPERM; if (copy_to_user(wrq->u.encoding.pointer,
break; keybuf,
} wrq->u.encoding.length))
/* 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))
ret = -EFAULT; ret = -EFAULT;
} }
}
break; break;
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT #ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5 #if WIRELESS_EXT > 5
case SIOCSIWESSID: case SIOCSIWESSID:
/* Check if disable */ {
if(wrq->u.data.flags == 0) char essidbuf[IW_ESSID_MAX_SIZE+1];
lp->filter_domains = 0; if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
else ret = -E2BIG;
/* Basic checking... */ break;
if(wrq->u.data.pointer != (caddr_t) 0) }
{ if (copy_from_user(essidbuf, wrq->u.essid.pointer,
char essid[IW_ESSID_MAX_SIZE + 1]; wrq->u.essid.length)) {
char * endp; ret = -EFAULT;
break;
/* Check the size of the string */ }
if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) ret = wavelan_set_essid(dev, NULL,
{ &(wrq->u),
ret = -E2BIG; essidbuf);
break; }
}
/* Copy the string in the driver */
if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.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;
}
}
break; break;
case SIOCGIWESSID: case SIOCGIWESSID:
/* Basic checking... */ {
if(wrq->u.data.pointer != (caddr_t) 0) char essidbuf[IW_ESSID_MAX_SIZE+1];
{ ret = wavelan_get_essid(dev, NULL,
char essid[IW_ESSID_MAX_SIZE + 1]; &(wrq->u),
essidbuf);
/* Is the domain ID active ? */ if (wrq->u.essid.pointer)
wrq->u.data.flags = lp->filter_domains; if ( copy_to_user(wrq->u.essid.pointer,
essidbuf,
/* Copy Domain ID into a string (Wavelan specific) */ wrq->u.essid.length) )
/* 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))
ret = -EFAULT; ret = -EFAULT;
} }
break; break;
case SIOCSIWAP: case SIOCSIWAP:
#ifdef DEBUG_IOCTL_INFO ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL);
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 */
break; break;
case SIOCGIWAP: case SIOCGIWAP:
/* Should get the real McCoy instead of own Ethernet address */ ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL);
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 */
break; break;
#endif /* WIRELESS_EXT > 5 */ #endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */ #endif /* WAVELAN_ROAMING_EXT */
...@@ -2216,225 +3034,84 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2216,225 +3034,84 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING #ifdef WAVELAN_ROAMING
case SIOCSIWMODE: case SIOCSIWMODE:
switch(wrq->u.mode) ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL);
{
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;
}
break; break;
case SIOCGIWMODE: case SIOCGIWMODE:
if(do_roaming) ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL);
wrq->u.mode = IW_MODE_INFRA;
else
wrq->u.mode = IW_MODE_ADHOC;
break; break;
#endif /* WAVELAN_ROAMING */ #endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE: case SIOCGIWRANGE:
/* Basic checking... */ {
if(wrq->u.data.pointer != (caddr_t) 0) struct iw_range range;
{ ret = wavelan_get_range(dev, NULL,
struct iw_range range; &(wrq->u),
(char *) &range);
/* Set the length (very important for backward compatibility) */ if (copy_to_user(wrq->u.data.pointer, &range,
wrq->u.data.length = sizeof(struct iw_range); sizeof(struct iw_range)))
ret = -EFAULT;
/* 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,
sizeof(struct iw_range)))
ret = -EFAULT;
}
break; break;
case SIOCGIWPRIV: case SIOCGIWPRIV:
/* Basic checking... */ /* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) 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 */ /* 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 */ /* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args,
sizeof(priv))) sizeof(wavelan_private_args)))
ret = -EFAULT; ret = -EFAULT;
} }
break; break;
#ifdef WIRELESS_SPY #ifdef WIRELESS_SPY
case SIOCSIWSPY: case SIOCSIWSPY:
/* Set the spy list */ {
struct sockaddr address[IW_MAX_SPY];
/* Check the number of addresses */ /* Check the number of addresses */
if(wrq->u.data.length > IW_MAX_SPY) if (wrq->u.data.length > IW_MAX_SPY) {
{
ret = -E2BIG; ret = -E2BIG;
break; break;
} }
lp->spy_number = wrq->u.data.length; /* Get the data in the driver */
if (wrq->u.data.pointer) {
/* If there is some addresses to copy */ if (copy_from_user((char *) address,
if(lp->spy_number > 0) wrq->u.data.pointer,
{ sizeof(struct sockaddr) *
struct sockaddr address[IW_MAX_SPY]; wrq->u.data.length)) {
int i; ret = -EFAULT;
break;
/* Copy addresses to the driver */ }
if(copy_from_user(address, wrq->u.data.pointer, } else if (wrq->u.data.length != 0) {
sizeof(struct sockaddr) * lp->spy_number)) ret = -EINVAL;
{ break;
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);
}
/* 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; break;
case SIOCGIWSPY: case SIOCGIWSPY:
/* Get the spy list and spy stats */ {
char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
/* Set the number of addresses */ sizeof(struct iw_quality))];
wrq->u.data.length = lp->spy_number; ret = wavelan_get_spy(dev, NULL, &(wrq->u),
buffer);
/* If the user want to have the addresses back... */ if (wrq->u.data.pointer) {
if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) if (copy_to_user(wrq->u.data.pointer,
{ buffer,
struct sockaddr address[IW_MAX_SPY]; (wrq->u.data.length *
int i; (sizeof(struct sockaddr) +
sizeof(struct iw_quality)))
/* Copy addresses from the lp structure */ ))
for(i = 0; i < lp->spy_number; i++) ret = -EFAULT;
{ }
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))
{
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; break;
#endif /* WIRELESS_SPY */ #endif /* WIRELESS_SPY */
...@@ -2446,34 +3123,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2446,34 +3123,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EPERM; ret = -EPERM;
break; break;
} }
psa.psa_quality_thr = *(wrq->u.name) & 0x0F; ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL);
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);
break; break;
case SIOCGIPQTHR: case SIOCGIPQTHR:
psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL);
(unsigned char *)&psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
break; break;
#ifdef WAVELAN_ROAMING #ifdef WAVELAN_ROAMING
case SIOCSIPROAM: case SIOCSIPROAM:
/* Note : should check if user == root */ /* Note : should check if user == root */
if(do_roaming && (*wrq->u.name)==0) ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL);
wv_roam_cleanup(dev);
else if(do_roaming==0 && (*wrq->u.name)!=0)
wv_roam_init(dev);
do_roaming = (*wrq->u.name);
break; break;
case SIOCGIPROAM: case SIOCGIPROAM:
*(wrq->u.name) = do_roaming; ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL);
break; break;
#endif /* WAVELAN_ROAMING */ #endif /* WAVELAN_ROAMING */
...@@ -2484,44 +3148,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2484,44 +3148,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
{ {
ret = -EPERM; ret = -EPERM;
} }
{
/* Check the number of intervals */ char buffer[16];
if(wrq->u.data.length > 16) /* Check the number of intervals */
{ if(wrq->u.data.length > 16)
ret = -E2BIG; {
break; ret = -E2BIG;
break;
} }
lp->his_number = wrq->u.data.length; /* Get the data in the driver */
if (wrq->u.data.pointer) {
/* If there is some addresses to copy */ if (copy_from_user(buffer,
if(lp->his_number > 0) wrq->u.data.pointer,
{ sizeof(struct sockaddr) *
/* Copy interval ranges to the driver */ wrq->u.data.length)) {
if(copy_from_user(lp->his_range, wrq->u.data.pointer, ret = -EFAULT;
sizeof(char) * lp->his_number)) break;
{ }
ret = -EFAULT; } else if (wrq->u.data.length != 0) {
break; ret = -EINVAL;
} break;
/* Reset structure... */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
} }
ret = wavelan_set_histo(dev, NULL, &(wrq->u),
buffer);
}
break; break;
case SIOCGIPHISTO: case SIOCGIPHISTO:
/* Set the number of intervals */ {
wrq->u.data.length = lp->his_number; long buffer[16];
ret = wavelan_get_histo(dev, NULL, &(wrq->u),
/* Give back the distribution statistics */ (char *) buffer);
if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) if (wrq->u.data.pointer) {
{ if (copy_to_user(wrq->u.data.pointer,
/* Copy data to the user buffer */ buffer,
if(copy_to_user(wrq->u.data.pointer, lp->his_sum, (wrq->u.data.length * sizeof(long))))
sizeof(long) * lp->his_number))
ret = -EFAULT; ret = -EFAULT;
}
} /* if(pointer != NULL) */ }
break; break;
#endif /* HISTOGRAM */ #endif /* HISTOGRAM */
...@@ -2531,14 +3195,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2531,14 +3195,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
/* ReEnable interrupts & restore flags */
wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE #ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif #endif
return ret; return ret;
} }
#endif /* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
...@@ -4530,7 +5192,11 @@ wavelan_attach(void) ...@@ -4530,7 +5192,11 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES; dev->watchdog_timeo = WATCHDOG_JIFFIES;
#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ #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 */ dev->do_ioctl = wavelan_ioctl; /* wireless extensions */
#endif /* WIRELESS_EXT > 12 */
dev->get_wireless_stats = wavelan_get_wireless_stats; dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif #endif
......
...@@ -394,6 +394,12 @@ ...@@ -394,6 +394,12 @@
* o control first busy loop in wv_82593_cmd() * o control first busy loop in wv_82593_cmd()
* o Extend spinlock protection in wv_hw_config() * 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: * Wishes & dreams:
* ---------------- * ----------------
* - Cleanup and integrate the roaming code * - Cleanup and integrate the roaming code
...@@ -430,6 +436,9 @@ ...@@ -430,6 +436,9 @@
#ifdef CONFIG_NET_RADIO #ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Wireless extensions */ #include <linux/wireless.h> /* Wireless extensions */
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif #endif
/* Pcmcia headers that we need */ /* Pcmcia headers that we need */
...@@ -498,7 +507,7 @@ ...@@ -498,7 +507,7 @@
/************************ CONSTANTS & MACROS ************************/ /************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW #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 #endif
/* Watchdog temporisation */ /* Watchdog temporisation */
...@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/ ...@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/
#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */
#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ #define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */
/*************************** WaveLAN Roaming **************************/ /*************************** WaveLAN Roaming **************************/
#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */
...@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq; ...@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq;
typedef struct net_local net_local; typedef struct net_local net_local;
typedef struct timer_list timer_list; 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 */ /* Basic types */
typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ 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