Commit 620554e4 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jeff Garzik

[PATCH] orinoco: wireless API 15 support

(patch from Moustafa Youssef, updated by Jim Carter and Pavel Roskin).
parent 5d558b7f
...@@ -463,6 +463,7 @@ ...@@ -463,6 +463,7 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h> #include <net/ieee80211.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -538,6 +539,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer ...@@ -538,6 +539,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
| HERMES_EV_WTERR | HERMES_EV_INFO \ | HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP ) | HERMES_EV_INFDROP )
#define MAX_RID_LEN 1024
static const struct iw_handler_def orinoco_handler_def;
/********************************************************************/ /********************************************************************/
/* Data tables */ /* Data tables */
/********************************************************************/ /********************************************************************/
...@@ -605,7 +610,6 @@ struct hermes_rx_descriptor { ...@@ -605,7 +610,6 @@ struct hermes_rx_descriptor {
/* Function prototypes */ /* Function prototypes */
/********************************************************************/ /********************************************************************/
static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int __orinoco_program_rids(struct net_device *dev); static int __orinoco_program_rids(struct net_device *dev);
static void __orinoco_set_multicast_list(struct net_device *dev); static void __orinoco_set_multicast_list(struct net_device *dev);
...@@ -1870,55 +1874,6 @@ __orinoco_set_multicast_list(struct net_device *dev) ...@@ -1870,55 +1874,6 @@ __orinoco_set_multicast_list(struct net_device *dev)
dev->flags &= ~IFF_PROMISC; dev->flags &= ~IFF_PROMISC;
} }
static int orinoco_reconfigure(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
unsigned long flags;
int err = 0;
if (priv->broken_disableport) {
schedule_work(&priv->reset_work);
return 0;
}
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
err = hermes_disable_port(hw, 0);
if (err) {
printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n",
dev->name);
priv->broken_disableport = 1;
goto out;
}
err = __orinoco_program_rids(dev);
if (err) {
printk(KERN_WARNING "%s: Unable to reconfigure card\n",
dev->name);
goto out;
}
err = hermes_enable_port(hw, 0);
if (err) {
printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
dev->name);
goto out;
}
out:
if (err) {
printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
schedule_work(&priv->reset_work);
err = 0;
}
orinoco_unlock(priv, &flags);
return err;
}
/* This must be called from user context, without locks held - use /* This must be called from user context, without locks held - use
* schedule_work() */ * schedule_work() */
static void orinoco_reset(struct net_device *dev) static void orinoco_reset(struct net_device *dev)
...@@ -2458,7 +2413,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, ...@@ -2458,7 +2413,7 @@ struct net_device *alloc_orinocodev(int sizeof_card,
dev->watchdog_timeo = HZ; /* 1 second timeout */ dev->watchdog_timeo = HZ; /* 1 second timeout */
dev->get_stats = orinoco_get_stats; dev->get_stats = orinoco_get_stats;
dev->get_wireless_stats = orinoco_get_wireless_stats; dev->get_wireless_stats = orinoco_get_wireless_stats;
dev->do_ioctl = orinoco_ioctl; dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
dev->change_mtu = orinoco_change_mtu; dev->change_mtu = orinoco_change_mtu;
dev->set_multicast_list = orinoco_set_multicast_list; dev->set_multicast_list = orinoco_set_multicast_list;
/* we use the default eth_mac_addr for setting the MAC addr */ /* we use the default eth_mac_addr for setting the MAC addr */
...@@ -2491,24 +2446,6 @@ void free_orinocodev(struct net_device *dev) ...@@ -2491,24 +2446,6 @@ void free_orinocodev(struct net_device *dev)
/* Wireless extensions */ /* Wireless extensions */
/********************************************************************/ /********************************************************************/
static int orinoco_hw_get_bssid(struct orinoco_private *priv,
char buf[ETH_ALEN])
{
hermes_t *hw = &priv->hw;
int err = 0;
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
ETH_ALEN, NULL, buf);
orinoco_unlock(priv, &flags);
return err;
}
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
char buf[IW_ESSID_MAX_SIZE+1]) char buf[IW_ESSID_MAX_SIZE+1])
{ {
...@@ -2634,140 +2571,201 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, ...@@ -2634,140 +2571,201 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0; return 0;
} }
static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) static int orinoco_ioctl_getname(struct net_device *dev,
struct iw_request_info *info,
char *name,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int err = 0;
int mode;
struct iw_range range;
int numrates; int numrates;
int i, k; int err;
err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
if (!err && (numrates > 2))
strcpy(name, "IEEE 802.11b");
else
strcpy(name, "IEEE 802.11-DS");
return 0;
}
static int orinoco_ioctl_getwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
unsigned long flags; unsigned long flags;
TRACE_ENTER(dev->name); if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
ap_addr->sa_family = ARPHRD_ETHER;
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
ETH_ALEN, NULL, ap_addr->sa_data);
orinoco_unlock(priv, &flags);
return err;
}
if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range))) static int orinoco_ioctl_setmode(struct net_device *dev,
return -EFAULT; struct iw_request_info *info,
u32 *mode,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
rrq->length = sizeof(range); if (priv->iw_mode == *mode)
return 0;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
mode = priv->iw_mode; switch (*mode) {
case IW_MODE_ADHOC:
if (!priv->has_ibss && !priv->has_port3)
err = -EOPNOTSUPP;
break;
case IW_MODE_INFRA:
break;
default:
err = -EOPNOTSUPP;
break;
}
if (err == -EINPROGRESS) {
priv->iw_mode = *mode;
set_port_type(priv);
}
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
memset(&range, 0, sizeof(range)); return err;
}
static int orinoco_ioctl_getmode(struct net_device *dev,
struct iw_request_info *info,
u32 *mode,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
*mode = priv->iw_mode;
return 0;
}
static int orinoco_ioctl_getiwrange(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *rrq,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int err = 0;
struct iw_range *range = (struct iw_range *) extra;
int numrates;
int i, k;
TRACE_ENTER(dev->name);
/* Much of this shamelessly taken from wvlan_cs.c. No idea rrq->length = sizeof(struct iw_range);
* what it all means -dgibson */ memset(range, 0, sizeof(struct iw_range));
range.we_version_compiled = WIRELESS_EXT;
range.we_version_source = 11;
range.min_nwid = range.max_nwid = 0; /* We don't use nwids */ range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 14;
/* Set available channels/frequencies */ /* Set available channels/frequencies */
range.num_channels = NUM_CHANNELS; range->num_channels = NUM_CHANNELS;
k = 0; k = 0;
for (i = 0; i < NUM_CHANNELS; i++) { for (i = 0; i < NUM_CHANNELS; i++) {
if (priv->channel_mask & (1 << i)) { if (priv->channel_mask & (1 << i)) {
range.freq[k].i = i + 1; range->freq[k].i = i + 1;
range.freq[k].m = channel_frequency[i] * 100000; range->freq[k].m = channel_frequency[i] * 100000;
range.freq[k].e = 1; range->freq[k].e = 1;
k++; k++;
} }
if (k >= IW_MAX_FREQUENCIES) if (k >= IW_MAX_FREQUENCIES)
break; break;
} }
range.num_frequency = k; range->num_frequency = k;
range->sensitivity = 3;
range.sensitivity = 3; if (priv->has_wep) {
range->max_encoding_tokens = ORINOCO_MAX_KEYS;
range->encoding_size[0] = SMALL_KEY_SIZE;
range->num_encoding_sizes = 1;
if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){ if (priv->has_big_wep) {
range->encoding_size[1] = LARGE_KEY_SIZE;
range->num_encoding_sizes = 2;
}
}
if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
/* Quality stats meaningless in ad-hoc mode */ /* Quality stats meaningless in ad-hoc mode */
range.max_qual.qual = 0;
range.max_qual.level = 0;
range.max_qual.noise = 0;
range.avg_qual.qual = 0;
range.avg_qual.level = 0;
range.avg_qual.noise = 0;
} else { } else {
range.max_qual.qual = 0x8b - 0x2f; range->max_qual.qual = 0x8b - 0x2f;
range.max_qual.level = 0x2f - 0x95 - 1; range->max_qual.level = 0x2f - 0x95 - 1;
range.max_qual.noise = 0x2f - 0x95 - 1; range->max_qual.noise = 0x2f - 0x95 - 1;
/* Need to get better values */ /* Need to get better values */
range.avg_qual.qual = 0x24; range->avg_qual.qual = 0x24;
range.avg_qual.level = 0xC2; range->avg_qual.level = 0xC2;
range.avg_qual.noise = 0x9E; range->avg_qual.noise = 0x9E;
} }
err = orinoco_hw_get_bitratelist(priv, &numrates, err = orinoco_hw_get_bitratelist(priv, &numrates,
range.bitrate, IW_MAX_BITRATES); range->bitrate, IW_MAX_BITRATES);
if (err) if (err)
return err; return err;
range.num_bitrates = numrates; range->num_bitrates = numrates;
/* Set an indication of the max TCP throughput in bit/s that we can /* Set an indication of the max TCP throughput in bit/s that we can
* expect using this interface. May be use for QoS stuff... * expect using this interface. May be use for QoS stuff...
* Jean II */ * Jean II */
if(numrates > 2) if (numrates > 2)
range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */ range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
else else
range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */ range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
range.min_rts = 0; range->min_rts = 0;
range.max_rts = 2347; range->max_rts = 2347;
range.min_frag = 256; range->min_frag = 256;
range.max_frag = 2346; range->max_frag = 2346;
if (orinoco_lock(priv, &flags) != 0) range->min_pmp = 0;
return -EBUSY; range->max_pmp = 65535000;
if (priv->has_wep) { range->min_pmt = 0;
range.max_encoding_tokens = ORINOCO_MAX_KEYS; range->max_pmt = 65535 * 1000; /* ??? */
range->pmp_flags = IW_POWER_PERIOD;
range.encoding_size[0] = SMALL_KEY_SIZE; range->pmt_flags = IW_POWER_TIMEOUT;
range.num_encoding_sizes = 1; range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
if (priv->has_big_wep) { range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
range.encoding_size[1] = LARGE_KEY_SIZE; range->retry_flags = IW_RETRY_LIMIT;
range.num_encoding_sizes = 2; range->r_time_flags = IW_RETRY_LIFETIME;
} range->min_retry = 0;
} else { range->max_retry = 65535; /* ??? */
range.num_encoding_sizes = 0; range->min_r_time = 0;
range.max_encoding_tokens = 0; range->max_r_time = 65535 * 1000; /* ??? */
}
orinoco_unlock(priv, &flags);
range.min_pmp = 0;
range.max_pmp = 65535000;
range.min_pmt = 0;
range.max_pmt = 65535 * 1000; /* ??? */
range.pmp_flags = IW_POWER_PERIOD;
range.pmt_flags = IW_POWER_TIMEOUT;
range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
range.num_txpower = 1;
range.txpower[0] = 15; /* 15dBm */
range.txpower_capa = IW_TXPOW_DBM;
range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
range.retry_flags = IW_RETRY_LIMIT;
range.r_time_flags = IW_RETRY_LIFETIME;
range.min_retry = 0;
range.max_retry = 65535; /* ??? */
range.min_r_time = 0;
range.max_r_time = 65535 * 1000; /* ??? */
if (copy_to_user(rrq->pointer, &range, sizeof(range)))
return -EFAULT;
TRACE_EXIT(dev->name); TRACE_EXIT(dev->name);
return 0; return 0;
} }
static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) static int orinoco_ioctl_setiwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *keybuf)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1; int index = (erq->flags & IW_ENCODE_INDEX) - 1;
...@@ -2775,8 +2773,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er ...@@ -2775,8 +2773,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
int enable = priv->wep_on; int enable = priv->wep_on;
int restricted = priv->wep_restrict; int restricted = priv->wep_restrict;
u16 xlen = 0; u16 xlen = 0;
int err = 0; int err = -EINPROGRESS; /* Call commit handler */
char keybuf[ORINOCO_MAX_KEY_SIZE];
unsigned long flags; unsigned long flags;
if (! priv->has_wep) if (! priv->has_wep)
...@@ -2789,9 +2786,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er ...@@ -2789,9 +2786,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep ) if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
return -E2BIG; return -E2BIG;
if (copy_from_user(keybuf, erq->pointer, erq->length))
return -EFAULT;
} }
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
...@@ -2865,12 +2859,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er ...@@ -2865,12 +2859,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
return err; return err;
} }
static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) static int orinoco_ioctl_getiwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *keybuf)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1; int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0; u16 xlen = 0;
char keybuf[ORINOCO_MAX_KEY_SIZE];
unsigned long flags; unsigned long flags;
if (! priv->has_wep) if (! priv->has_wep)
...@@ -2899,51 +2895,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er ...@@ -2899,51 +2895,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er
memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE); memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
if (erq->pointer) {
if (copy_to_user(erq->pointer, keybuf, xlen))
return -EFAULT;
}
return 0; return 0;
} }
static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) static int orinoco_ioctl_setessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *essidbuf)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
char essidbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags; unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
* anyway... - Jean II */ * anyway... - Jean II */
memset(&essidbuf, 0, sizeof(essidbuf)); /* Hum... Should not use Wireless Extension constant (may change),
* should use our own... - Jean II */
if (erq->flags) { if (erq->length > IW_ESSID_MAX_SIZE)
/* iwconfig includes the NUL in the specified length */
if (erq->length > IW_ESSID_MAX_SIZE+1)
return -E2BIG; return -E2BIG;
if (copy_from_user(&essidbuf, erq->pointer, erq->length))
return -EFAULT;
essidbuf[IW_ESSID_MAX_SIZE] = '\0';
}
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid)); /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
/* If not ANY, get the new ESSID */
if (erq->flags) {
memcpy(priv->desired_essid, essidbuf, erq->length);
}
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return 0; return -EINPROGRESS; /* Call commit handler */
} }
static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) static int orinoco_ioctl_getessid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *essidbuf)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
char essidbuf[IW_ESSID_MAX_SIZE+1];
int active; int active;
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
...@@ -2957,51 +2949,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) ...@@ -2957,51 +2949,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
} else { } else {
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf)); memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
} }
erq->flags = 1; erq->flags = 1;
erq->length = strlen(essidbuf) + 1; erq->length = strlen(essidbuf) + 1;
if (erq->pointer)
if (copy_to_user(erq->pointer, essidbuf, erq->length))
return -EFAULT;
TRACE_EXIT(dev->name); TRACE_EXIT(dev->name);
return 0; return 0;
} }
static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) static int orinoco_ioctl_setnick(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *nrq,
char *nickbuf)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
char nickbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags; unsigned long flags;
if (nrq->length > IW_ESSID_MAX_SIZE) if (nrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG; return -E2BIG;
memset(nickbuf, 0, sizeof(nickbuf));
if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
return -EFAULT;
nickbuf[nrq->length] = '\0';
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
memcpy(priv->nick, nickbuf, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick));
memcpy(priv->nick, nickbuf, nrq->length);
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return 0; return -EINPROGRESS; /* Call commit handler */
} }
static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) static int orinoco_ioctl_getnick(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *nrq,
char *nickbuf)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
char nickbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags; unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
...@@ -3012,17 +2999,18 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) ...@@ -3012,17 +2999,18 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
nrq->length = strlen(nickbuf)+1; nrq->length = strlen(nickbuf)+1;
if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
return -EFAULT;
return 0; return 0;
} }
static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) static int orinoco_ioctl_setfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int chan = -1; int chan = -1;
unsigned long flags; unsigned long flags;
int err = -EINPROGRESS; /* Call commit handler */
/* We can only use this in Ad-Hoc demo mode to set the operating /* We can only use this in Ad-Hoc demo mode to set the operating
* frequency, or in IBSS mode to set the frequency where the IBSS * frequency, or in IBSS mode to set the frequency where the IBSS
...@@ -3055,10 +3043,33 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) ...@@ -3055,10 +3043,33 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
priv->channel = chan; priv->channel = chan;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err;
}
static int orinoco_ioctl_getfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int tmp;
/* Locking done in there */
tmp = orinoco_hw_get_freq(priv);
if (tmp < 0) {
return tmp;
}
frq->m = tmp;
frq->e = 1;
return 0; return 0;
} }
static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) static int orinoco_ioctl_getsens(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *srq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
...@@ -3084,7 +3095,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) ...@@ -3084,7 +3095,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
return 0; return 0;
} }
static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) static int orinoco_ioctl_setsens(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *srq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int val = srq->value; int val = srq->value;
...@@ -3101,10 +3115,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) ...@@ -3101,10 +3115,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
priv->ap_density = val; priv->ap_density = val;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return 0; return -EINPROGRESS; /* Call commit handler */
} }
static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) static int orinoco_ioctl_setrts(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rrq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int val = rrq->value; int val = rrq->value;
...@@ -3122,13 +3139,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) ...@@ -3122,13 +3139,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
priv->rts_thresh = val; priv->rts_thresh = val;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return -EINPROGRESS; /* Call commit handler */
}
static int orinoco_ioctl_getrts(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rrq,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
rrq->value = priv->rts_thresh;
rrq->disabled = (rrq->value == 2347);
rrq->fixed = 1;
return 0; return 0;
} }
static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) static int orinoco_ioctl_setfrag(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *frq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int err = 0; int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags; unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
...@@ -3160,11 +3194,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) ...@@ -3160,11 +3194,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
return err; return err;
} }
static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) static int orinoco_ioctl_getfrag(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *frq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err = 0; int err;
u16 val; u16 val;
unsigned long flags; unsigned long flags;
...@@ -3197,10 +3234,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) ...@@ -3197,10 +3234,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
return err; return err;
} }
static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) static int orinoco_ioctl_setrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rrq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int err = 0;
int ratemode = -1; int ratemode = -1;
int bitrate; /* 100s of kilobits */ int bitrate; /* 100s of kilobits */
int i; int i;
...@@ -3236,10 +3275,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) ...@@ -3236,10 +3275,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
priv->bitratemode = ratemode; priv->bitratemode = ratemode;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err; return -EINPROGRESS;
} }
static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) static int orinoco_ioctl_getrate(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rrq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
...@@ -3304,10 +3346,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) ...@@ -3304,10 +3346,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
return err; return err;
} }
static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) static int orinoco_ioctl_setpower(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *prq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int err = 0; int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags; unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
...@@ -3356,7 +3401,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) ...@@ -3356,7 +3401,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
return err; return err;
} }
static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) static int orinoco_ioctl_getpower(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *prq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
...@@ -3404,7 +3452,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) ...@@ -3404,7 +3452,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
return err; return err;
} }
static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) static int orinoco_ioctl_getretry(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rrq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
...@@ -3455,10 +3506,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) ...@@ -3455,10 +3506,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
return err; return err;
} }
static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) static int orinoco_ioctl_reset(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int val = *( (int *) wrq->u.name );
if (! capable(CAP_NET_ADMIN))
return -EPERM;
if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
/* Firmware reset */
orinoco_reset(dev);
} else {
printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
schedule_work(&priv->reset_work);
}
return 0;
}
static int orinoco_ioctl_setibssport(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int val = *( (int *) extra );
unsigned long flags; unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
...@@ -3470,28 +3549,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) ...@@ -3470,28 +3549,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
set_port_type(priv); set_port_type(priv);
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return 0; return -EINPROGRESS; /* Call commit handler */
} }
static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) static int orinoco_ioctl_getibssport(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int *val = (int *)wrq->u.name; int *val = (int *) extra;
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
*val = priv->ibss_port; *val = priv->ibss_port;
orinoco_unlock(priv, &flags);
return 0; return 0;
} }
static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) static int orinoco_ioctl_setport3(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int val = *( (int *) wrq->u.name ); int val = *( (int *) extra );
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
...@@ -3520,51 +3599,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) ...@@ -3520,51 +3599,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
err = -EINVAL; err = -EINVAL;
} }
if (! err) if (! err) {
/* Actually update the mode we are using */ /* Actually update the mode we are using */
set_port_type(priv); set_port_type(priv);
err = -EINPROGRESS;
}
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err; return err;
} }
static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) static int orinoco_ioctl_getport3(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int *val = (int *) extra;
*val = priv->prefer_port3;
return 0;
}
static int orinoco_ioctl_setpreamble(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
int *val = (int *)wrq->u.name;
unsigned long flags; unsigned long flags;
int val;
if (! priv->has_preamble)
return -EOPNOTSUPP;
/* 802.11b has recently defined some short preamble.
* Basically, the Phy header has been reduced in size.
* This increase performance, especially at high rates
* (the preamble is transmitted at 1Mb/s), unfortunately
* this give compatibility troubles... - Jean II */
val = *( (int *) extra );
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
*val = priv->prefer_port3; if (val)
priv->preamble = 1;
else
priv->preamble = 0;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return -EINPROGRESS; /* Call commit handler */
}
static int orinoco_ioctl_getpreamble(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int *val = (int *) extra;
if (! priv->has_preamble)
return -EOPNOTSUPP;
*val = priv->preamble;
return 0; return 0;
} }
/* ioctl interface to hermes_read_ltv()
* To use with iwpriv, pass the RID as the token argument, e.g.
* iwpriv get_rid [0xfc00]
* At least Wireless Tools 25 is required to use iwpriv.
* For Wireless Tools 25 and 26 append "dummy" are the end. */
static int orinoco_ioctl_getrid(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data,
char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
int rid = data->flags;
u16 length;
int err;
unsigned long flags;
/* It's a "get" function, but we don't want users to access the
* WEP key and other raw firmware data */
if (! capable(CAP_NET_ADMIN))
return -EPERM;
if (rid < 0xfc00 || rid > 0xffff)
return -EINVAL;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
extra);
if (err)
goto out;
data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
MAX_RID_LEN);
out:
orinoco_unlock(priv, &flags);
return err;
}
/* Spy is used for link quality/strength measurements in Ad-Hoc mode /* Spy is used for link quality/strength measurements in Ad-Hoc mode
* Jean II */ * Jean II */
static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) static int orinoco_ioctl_setspy(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *srq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct sockaddr address[IW_MAX_SPY]; struct sockaddr *address = (struct sockaddr *) extra;
int number = srq->length; int number = srq->length;
int i; int i;
int err = 0;
unsigned long flags; unsigned long flags;
/* Check the number of addresses */
if (number > IW_MAX_SPY)
return -E2BIG;
/* Get the data in the driver */
if (srq->pointer) {
if (copy_from_user(address, srq->pointer,
sizeof(struct sockaddr) * number))
return -EFAULT;
}
/* Make sure nobody mess with the structure while we do */ /* Make sure nobody mess with the structure while we do */
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
...@@ -3588,14 +3747,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) ...@@ -3588,14 +3747,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
/* Now, let the others play */ /* Now, let the others play */
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return err; /* Do NOT call commit handler */
return 0;
} }
static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) static int orinoco_ioctl_getspy(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *srq,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct sockaddr address[IW_MAX_SPY]; struct sockaddr *address = (struct sockaddr *) extra;
struct iw_quality spy_stat[IW_MAX_SPY];
int number; int number;
int i; int i;
unsigned long flags; unsigned long flags;
...@@ -3604,7 +3766,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) ...@@ -3604,7 +3766,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
return -EBUSY; return -EBUSY;
number = priv->spy_number; number = priv->spy_number;
if ((number > 0) && (srq->pointer)) { /* Create address struct */
for (i = 0; i < number; i++) {
memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN);
address[i].sa_family = AF_UNIX;
}
if (number > 0) {
/* Create address struct */ /* Create address struct */
for (i = 0; i < number; i++) { for (i = 0; i < number; i++) {
memcpy(address[i].sa_data, priv->spy_address[i], memcpy(address[i].sa_data, priv->spy_address[i],
...@@ -3615,344 +3782,153 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) ...@@ -3615,344 +3782,153 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
/* In theory, we should disable irqs while copying the stats /* In theory, we should disable irqs while copying the stats
* because the rx path might update it in the middle... * because the rx path might update it in the middle...
* Bah, who care ? - Jean II */ * Bah, who care ? - Jean II */
memcpy(&spy_stat, priv->spy_stat, memcpy(extra + (sizeof(struct sockaddr) * number),
sizeof(struct iw_quality) * IW_MAX_SPY); priv->spy_stat, sizeof(struct iw_quality) * number);
for (i=0; i < number; i++)
priv->spy_stat[i].updated = 0;
} }
/* Reset updated flags. */
for (i = 0; i < number; i++)
priv->spy_stat[i].updated = 0;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
/* Push stuff to user space */
srq->length = number; srq->length = number;
if(copy_to_user(srq->pointer, address,
sizeof(struct sockaddr) * number))
return -EFAULT;
if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
&spy_stat, sizeof(struct iw_quality) * number))
return -EFAULT;
return 0; return 0;
} }
static int /* Commit handler, called after set operations */
orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int orinoco_ioctl_commit(struct net_device *dev,
struct iw_request_info *info,
void *wrqu,
char *extra)
{ {
struct orinoco_private *priv = netdev_priv(dev); struct orinoco_private *priv = netdev_priv(dev);
struct iwreq *wrq = (struct iwreq *)rq; struct hermes *hw = &priv->hw;
int err = 0;
int tmp;
int changed = 0;
unsigned long flags; unsigned long flags;
int err = 0;
TRACE_ENTER(dev->name); if (!priv->open)
return 0;
/* In theory, we could allow most of the the SET stuff to be
* done. In practice, the lapse of time at startup when the
* card is not ready is very short, so why bother... Note
* that netif_device_present is different from up/down
* (ifconfig), when the device is not yet up, it is usually
* already ready... Jean II */
if (! netif_device_present(dev))
return -ENODEV;
switch (cmd) {
case SIOCGIWNAME:
strcpy(wrq->u.name, "IEEE 802.11-DS");
break;
case SIOCGIWAP:
wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
break;
case SIOCGIWRANGE:
err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
break;
case SIOCSIWMODE:
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
switch (wrq->u.mode) {
case IW_MODE_ADHOC:
if (! (priv->has_ibss || priv->has_port3) )
err = -EINVAL;
else {
priv->iw_mode = IW_MODE_ADHOC;
changed = 1;
}
break;
case IW_MODE_INFRA:
priv->iw_mode = IW_MODE_INFRA;
changed = 1;
break;
default: if (priv->broken_disableport) {
err = -EINVAL; orinoco_reset(dev);
break; return 0;
} }
set_port_type(priv);
orinoco_unlock(priv, &flags);
break;
case SIOCGIWMODE:
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return err;
wrq->u.mode = priv->iw_mode;
orinoco_unlock(priv, &flags);
break;
case SIOCSIWENCODE:
err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
if (! err)
changed = 1;
break;
case SIOCGIWENCODE: err = hermes_disable_port(hw, 0);
if (! capable(CAP_NET_ADMIN)) { if (err) {
err = -EPERM; printk(KERN_WARNING "%s: Unable to disable port "
break; "while reconfiguring card\n", dev->name);
priv->broken_disableport = 1;
goto out;
} }
err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding); err = __orinoco_program_rids(dev);
break; if (err) {
printk(KERN_WARNING "%s: Unable to reconfigure card\n",
case SIOCSIWESSID: dev->name);
err = orinoco_ioctl_setessid(dev, &wrq->u.essid); goto out;
if (! err)
changed = 1;
break;
case SIOCGIWESSID:
err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
break;
case SIOCSIWNICKN:
err = orinoco_ioctl_setnick(dev, &wrq->u.data);
if (! err)
changed = 1;
break;
case SIOCGIWNICKN:
err = orinoco_ioctl_getnick(dev, &wrq->u.data);
break;
case SIOCGIWFREQ:
tmp = orinoco_hw_get_freq(priv);
if (tmp < 0) {
err = tmp;
} else {
wrq->u.freq.m = tmp;
wrq->u.freq.e = 1;
} }
break;
case SIOCSIWFREQ:
err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
if (! err)
changed = 1;
break;
case SIOCGIWSENS:
err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
break;
case SIOCSIWSENS: err = hermes_enable_port(hw, 0);
err = orinoco_ioctl_setsens(dev, &wrq->u.sens); if (err) {
if (! err) printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
changed = 1; dev->name);
break; goto out;
}
case SIOCGIWRTS:
wrq->u.rts.value = priv->rts_thresh;
wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
wrq->u.rts.fixed = 1;
break;
case SIOCSIWRTS:
err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
if (! err)
changed = 1;
break;
case SIOCSIWFRAG:
err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
if (! err)
changed = 1;
break;
case SIOCGIWFRAG:
err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
break;
case SIOCSIWRATE:
err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
if (! err)
changed = 1;
break;
case SIOCGIWRATE:
err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
break;
case SIOCSIWPOWER:
err = orinoco_ioctl_setpower(dev, &wrq->u.power);
if (! err)
changed = 1;
break;
case SIOCGIWPOWER:
err = orinoco_ioctl_getpower(dev, &wrq->u.power);
break;
case SIOCGIWTXPOW:
/* The card only supports one tx power, so this is easy */
wrq->u.txpower.value = 15; /* dBm */
wrq->u.txpower.fixed = 1;
wrq->u.txpower.disabled = 0;
wrq->u.txpower.flags = IW_TXPOW_DBM;
break;
case SIOCSIWRETRY:
err = -EOPNOTSUPP;
break;
case SIOCGIWRETRY:
err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
break;
case SIOCSIWSPY: out:
err = orinoco_ioctl_setspy(dev, &wrq->u.data); if (err) {
break; printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
schedule_work(&priv->reset_work);
err = 0;
}
case SIOCGIWSPY: orinoco_unlock(priv, &flags);
err = orinoco_ioctl_getspy(dev, &wrq->u.data); return err;
break; }
case SIOCGIWPRIV: static const struct iw_priv_args orinoco_privtab[] = {
if (wrq->u.data.pointer) {
struct iw_priv_args privtab[] = {
{ SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
{ SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
{ SIOCIWFIRSTPRIV + 0x2, { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
0, "set_port3" }, 0, "set_port3" },
{ SIOCIWFIRSTPRIV + 0x3, 0, { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
"get_port3" }, "get_port3" },
{ SIOCIWFIRSTPRIV + 0x4, { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
0, "set_preamble" }, 0, "set_preamble" },
{ SIOCIWFIRSTPRIV + 0x5, 0, { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
"get_preamble" }, "get_preamble" },
{ SIOCIWFIRSTPRIV + 0x6, { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
0, "set_ibssport" }, 0, "set_ibssport" },
{ SIOCIWFIRSTPRIV + 0x7, 0, { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
"get_ibssport" }, "get_ibssport" },
}; { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
"get_rid" },
wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]); };
if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
err = -EFAULT;
}
break;
case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
}
printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
schedule_work(&priv->reset_work);
break;
case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
}
err = orinoco_ioctl_setport3(dev, wrq);
if (! err)
changed = 1;
break;
case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
err = orinoco_ioctl_getport3(dev, wrq);
break;
case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
}
/* 802.11b has recently defined some short preamble.
* Basically, the Phy header has been reduced in size.
* This increase performance, especially at high rates
* (the preamble is transmitted at 1Mb/s), unfortunately
* this give compatibility troubles... - Jean II */
if(priv->has_preamble) {
int val = *( (int *) wrq->u.name );
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
if (val)
priv->preamble = 1;
else
priv->preamble = 0;
orinoco_unlock(priv, &flags);
changed = 1;
} else
err = -EOPNOTSUPP;
break;
case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
if(priv->has_preamble) {
int *val = (int *)wrq->u.name;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
*val = priv->preamble;
orinoco_unlock(priv, &flags);
} else
err = -EOPNOTSUPP;
break;
case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
if (! capable(CAP_NET_ADMIN)) {
err = -EPERM;
break;
}
err = orinoco_ioctl_setibssport(dev, wrq);
if (! err)
changed = 1;
break;
case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
err = orinoco_ioctl_getibssport(dev, wrq);
break;
default: /*
err = -EOPNOTSUPP; * Structures to export the Wireless Handlers
} */
if (! err && changed && netif_running(dev)) { static const iw_handler orinoco_handler[] = {
err = orinoco_reconfigure(dev); [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
} [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
[SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
[SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
[SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
[SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
[SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
[SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
[SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
[SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
[SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
[SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
[SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
[SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
[SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
[SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
[SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
[SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
[SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
[SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
[SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
[SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
[SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
[SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
[SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
[SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
[SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
};
TRACE_EXIT(dev->name);
return err; /*
} Added typecasting since we no longer use iwreq_data -- Moustafa
*/
static const iw_handler orinoco_private_handler[] = {
[0] (iw_handler) orinoco_ioctl_reset,
[1] (iw_handler) orinoco_ioctl_reset,
[2] (iw_handler) orinoco_ioctl_setport3,
[3] (iw_handler) orinoco_ioctl_getport3,
[4] (iw_handler) orinoco_ioctl_setpreamble,
[5] (iw_handler) orinoco_ioctl_getpreamble,
[6] (iw_handler) orinoco_ioctl_setibssport,
[7] (iw_handler) orinoco_ioctl_getibssport,
[9] (iw_handler) orinoco_ioctl_getrid,
};
static const struct iw_handler_def orinoco_handler_def = {
.num_standard = ARRAY_SIZE(orinoco_handler),
.num_private = ARRAY_SIZE(orinoco_private_handler),
.num_private_args = ARRAY_SIZE(orinoco_privtab),
.standard = orinoco_handler,
.private = orinoco_private_handler,
.private_args = orinoco_privtab,
};
/********************************************************************/ /********************************************************************/
/* Debugging */ /* Debugging */
......
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