Commit 9b7c8489 authored by Jeff Garzik's avatar Jeff Garzik
parents eff4b1fe 4edac92f
......@@ -25,6 +25,15 @@ config NET_RADIO
the tools from
<http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
config NET_WIRELESS_RTNETLINK
bool "Wireless Extension API over RtNetlink"
---help---
Support the Wireless Extension API over the RtNetlink socket
in addition to the traditional ioctl interface (selected above).
For now, few tools use this facility, but it might grow in the
future. The only downside is that it adds 4.5 kB to your kernel.
# Note : the cards are obsolete (can't buy them anymore), but the drivers
# are not, as people are still using them...
comment "Obsolete Wireless cards support (pre-802.11)"
......
......@@ -769,6 +769,11 @@ typedef struct {
u16 atimWindow;
} BSSListRid;
typedef struct {
BSSListRid bss;
struct list_head list;
} BSSListElement;
typedef struct {
u8 rssipct;
u8 rssidBm;
......@@ -902,6 +907,7 @@ static char swversion[] = "2.1";
#define NUM_MODULES 2
#define MIC_MSGLEN_MAX 2400
#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
#define AIRO_DEF_MTU 2312
typedef struct {
u32 size; // size
......@@ -1119,6 +1125,8 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket,
static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi);
static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm);
static void airo_networks_free(struct airo_info *ai);
struct airo_info {
struct net_device_stats stats;
struct net_device *dev;
......@@ -1150,7 +1158,7 @@ struct airo_info {
#define FLAG_COMMIT 13
#define FLAG_RESET 14
#define FLAG_FLASHING 15
#define JOB_MASK 0x1ff0000
#define JOB_MASK 0x2ff0000
#define JOB_DIE 16
#define JOB_XMIT 17
#define JOB_XMIT11 18
......@@ -1160,6 +1168,7 @@ struct airo_info {
#define JOB_EVENT 22
#define JOB_AUTOWEP 23
#define JOB_WSTATS 24
#define JOB_SCAN_RESULTS 25
int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
unsigned short *flash;
......@@ -1176,7 +1185,7 @@ struct airo_info {
} xmit, xmit11;
struct net_device *wifidev;
struct iw_statistics wstats; // wireless stats
unsigned long scan_timestamp; /* Time started to scan */
unsigned long scan_timeout; /* Time scan should be read */
struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
/* MIC stuff */
......@@ -1198,6 +1207,10 @@ struct airo_info {
APListRid *APList;
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
char proc_name[IFNAMSIZ];
struct list_head network_list;
struct list_head network_free_list;
BSSListElement *networks;
};
static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
......@@ -1216,6 +1229,22 @@ static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime);
static int flashputbuf(struct airo_info *ai);
static int flashrestart(struct airo_info *ai,struct net_device *dev);
#define airo_print(type, name, fmt, args...) \
{ printk(type "airo(%s): " fmt "\n", name, ##args); }
#define airo_print_info(name, fmt, args...) \
airo_print(KERN_INFO, name, fmt, ##args)
#define airo_print_dbg(name, fmt, args...) \
airo_print(KERN_DEBUG, name, fmt, ##args)
#define airo_print_warn(name, fmt, args...) \
airo_print(KERN_WARNING, name, fmt, ##args)
#define airo_print_err(name, fmt, args...) \
airo_print(KERN_ERR, name, fmt, ##args)
/***********************************************************************
* MIC ROUTINES *
***********************************************************************
......@@ -1294,7 +1323,7 @@ static int micsetup(struct airo_info *ai) {
ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
if (ai->tfm == NULL) {
printk(KERN_ERR "airo: failed to load transform for AES\n");
airo_print_err(ai->dev->name, "failed to load transform for AES");
return ERROR;
}
......@@ -1726,11 +1755,11 @@ static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lo
wkr.kindex = cpu_to_le16(wkr.kindex);
wkr.klen = cpu_to_le16(wkr.klen);
rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock);
if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc);
if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
if (perm) {
rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock);
if (rc!=SUCCESS) {
printk(KERN_ERR "airo: WEP_PERM set %x\n", rc);
airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
}
}
return rc;
......@@ -1909,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
struct airo_info *ai = dev->priv;
if (!skb) {
printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__);
airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__);
return 0;
}
npacks = skb_queue_len (&ai->txq);
......@@ -1955,8 +1984,8 @@ static int mpi_send_packet (struct net_device *dev)
/* get a packet to send */
if ((skb = skb_dequeue(&ai->txq)) == 0) {
printk (KERN_ERR
"airo: %s: Dequeue'd zero in send_packet()\n",
airo_print_err(dev->name,
"%s: Dequeue'd zero in send_packet()",
__FUNCTION__);
return 0;
}
......@@ -2108,7 +2137,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
u32 *fids = priv->fids;
if ( skb == NULL ) {
printk( KERN_ERR "airo: skb == NULL!!!\n" );
airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
return 0;
}
......@@ -2179,7 +2208,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
}
if ( skb == NULL ) {
printk( KERN_ERR "airo: skb == NULL!!!\n" );
airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__);
return 0;
}
......@@ -2364,6 +2393,8 @@ void stop_airo_card( struct net_device *dev, int freeres )
dev_kfree_skb(skb);
}
airo_networks_free (ai);
kfree(ai->flash);
kfree(ai->rssi);
kfree(ai->APList);
......@@ -2434,7 +2465,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
cmd.parm2 = MPI_MAX_FIDS;
rc=issuecommand(ai, &cmd, &rsp);
if (rc != SUCCESS) {
printk(KERN_ERR "airo: Couldn't allocate RX FID\n");
airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
return rc;
}
......@@ -2462,7 +2493,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
rc=issuecommand(ai, &cmd, &rsp);
if (rc != SUCCESS) {
printk(KERN_ERR "airo: Couldn't allocate TX FID\n");
airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
return rc;
}
......@@ -2476,7 +2507,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
cmd.parm2 = 1; /* Magic number... */
rc=issuecommand(ai, &cmd, &rsp);
if (rc != SUCCESS) {
printk(KERN_ERR "airo: Couldn't allocate RID\n");
airo_print_err(ai->dev->name, "Couldn't allocate RID");
return rc;
}
......@@ -2508,25 +2539,25 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
aux_len = AUXMEMSIZE;
if (!request_mem_region(mem_start, mem_len, name)) {
printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
(int)mem_start, (int)mem_len, name);
goto out;
}
if (!request_mem_region(aux_start, aux_len, name)) {
printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n",
airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
(int)aux_start, (int)aux_len, name);
goto free_region1;
}
ai->pcimem = ioremap(mem_start, mem_len);
if (!ai->pcimem) {
printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
(int)mem_start, (int)mem_len, name);
goto free_region2;
}
ai->pciaux = ioremap(aux_start, aux_len);
if (!ai->pciaux) {
printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n",
airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
(int)aux_start, (int)aux_len, name);
goto free_memmap;
}
......@@ -2534,7 +2565,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
/* Reserve PKTSIZE for each fid and 2K for the Rids */
ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
if (!ai->shared) {
printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n",
airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d",
PCI_SHARED_LEN);
goto free_auxmap;
}
......@@ -2626,7 +2657,7 @@ static void wifi_setup(struct net_device *dev)
dev->type = ARPHRD_IEEE80211;
dev->hard_header_len = ETH_HLEN;
dev->mtu = 2312;
dev->mtu = AIRO_DEF_MTU;
dev->addr_len = ETH_ALEN;
dev->tx_queue_len = 100;
......@@ -2670,6 +2701,42 @@ static int reset_card( struct net_device *dev , int lock) {
return 0;
}
#define MAX_NETWORK_COUNT 64
static int airo_networks_allocate(struct airo_info *ai)
{
if (ai->networks)
return 0;
ai->networks =
kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement),
GFP_KERNEL);
if (!ai->networks) {
airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
return -ENOMEM;
}
return 0;
}
static void airo_networks_free(struct airo_info *ai)
{
if (!ai->networks)
return;
kfree(ai->networks);
ai->networks = NULL;
}
static void airo_networks_initialize(struct airo_info *ai)
{
int i;
INIT_LIST_HEAD(&ai->network_free_list);
INIT_LIST_HEAD(&ai->network_list);
for (i = 0; i < MAX_NETWORK_COUNT; i++)
list_add_tail(&ai->networks[i].list,
&ai->network_free_list);
}
static struct net_device *_init_airo_card( unsigned short irq, int port,
int is_pcmcia, struct pci_dev *pci,
struct device *dmdev )
......@@ -2681,22 +2748,22 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
/* Create the network device object. */
dev = alloc_etherdev(sizeof(*ai));
if (!dev) {
printk(KERN_ERR "airo: Couldn't alloc_etherdev\n");
airo_print_err("", "Couldn't alloc_etherdev");
return NULL;
}
if (dev_alloc_name(dev, dev->name) < 0) {
printk(KERN_ERR "airo: Couldn't get name!\n");
airo_print_err("", "Couldn't get name!");
goto err_out_free;
}
ai = dev->priv;
ai->wifidev = NULL;
ai->flags = 0;
ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
printk(KERN_DEBUG "airo: Found an MPI350 card\n");
airo_print_dbg(dev->name, "Found an MPI350 card");
set_bit(FLAG_MPI, &ai->flags);
}
ai->dev = dev;
spin_lock_init(&ai->aux_lock);
sema_init(&ai->sem, 1);
ai->config.len = 0;
......@@ -2711,6 +2778,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
if (rc)
goto err_out_thr;
if (airo_networks_allocate (ai))
goto err_out_unlink;
airo_networks_initialize (ai);
/* The Airo-specific entries in the device structure. */
if (test_bit(FLAG_MPI,&ai->flags)) {
skb_queue_head_init (&ai->txq);
......@@ -2732,33 +2803,33 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
SET_NETDEV_DEV(dev, dmdev);
reset_card (dev, 1);
msleep(400);
rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
if (rc) {
printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
airo_print_err(dev->name, "register interrupt %d failed, rc %d",
irq, rc);
goto err_out_unlink;
}
if (!is_pcmcia) {
if (!request_region( dev->base_addr, 64, dev->name )) {
rc = -EBUSY;
printk(KERN_ERR "airo: Couldn't request region\n");
airo_print_err(dev->name, "Couldn't request region");
goto err_out_irq;
}
}
if (test_bit(FLAG_MPI,&ai->flags)) {
if (mpi_map_card(ai, pci, dev->name)) {
printk(KERN_ERR "airo: Could not map memory\n");
airo_print_err(dev->name, "Could not map memory");
goto err_out_res;
}
}
if (probe) {
if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" );
airo_print_err(dev->name, "MAC could not be enabled" );
rc = -EIO;
goto err_out_map;
}
......@@ -2769,21 +2840,20 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
rc = register_netdev(dev);
if (rc) {
printk(KERN_ERR "airo: Couldn't register_netdev\n");
airo_print_err(dev->name, "Couldn't register_netdev");
goto err_out_map;
}
ai->wifidev = init_wifidev(ai, dev);
set_bit(FLAG_REGISTERED,&ai->flags);
printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
dev->name,
airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
/* Allocate the transmit buffers */
if (probe && !test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2);
ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
setup_proc_entry( dev, dev->priv ); /* XXX check for failure */
netif_start_queue(dev);
......@@ -2840,16 +2910,16 @@ int reset_airo_card( struct net_device *dev )
return -1;
if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" );
airo_print_err(dev->name, "MAC could not be enabled");
return -1;
}
printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name,
airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* Allocate the transmit buffers if needed */
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ )
ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2);
ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2);
enable_interrupts( ai );
netif_wake_queue(dev);
......@@ -2875,6 +2945,65 @@ static void airo_send_event(struct net_device *dev) {
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
}
static void airo_process_scan_results (struct airo_info *ai) {
union iwreq_data wrqu;
BSSListRid BSSList;
int rc;
BSSListElement * loop_net;
BSSListElement * tmp_net;
/* Blow away current list of scan results */
list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
list_move_tail (&loop_net->list, &ai->network_free_list);
/* Don't blow away ->list, just BSS data */
memset (loop_net, 0, sizeof (loop_net->bss));
}
/* Try to read the first entry of the scan result */
rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0);
if((rc) || (BSSList.index == 0xffff)) {
/* No scan results */
goto out;
}
/* Read and parse all entries */
tmp_net = NULL;
while((!rc) && (BSSList.index != 0xffff)) {
/* Grab a network off the free list */
if (!list_empty(&ai->network_free_list)) {
tmp_net = list_entry(ai->network_free_list.next,
BSSListElement, list);
list_del(ai->network_free_list.next);
}
if (tmp_net != NULL) {
memcpy(tmp_net, &BSSList, sizeof(tmp_net->bss));
list_add_tail(&tmp_net->list, &ai->network_list);
tmp_net = NULL;
}
/* Read next entry */
rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
&BSSList, sizeof(BSSList), 0);
}
out:
ai->scan_timeout = 0;
clear_bit(JOB_SCAN_RESULTS, &ai->flags);
up(&ai->sem);
/* Send an empty event to user space.
* We don't send the received data on
* the event because it would require
* us to do complex transcoding, and
* we want to minimise the work done in
* the irq handler. Use a request to
* extract the data - Jean II */
wrqu.data.length = 0;
wrqu.data.flags = 0;
wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
}
static int airo_thread(void *data) {
struct net_device *dev = data;
struct airo_info *ai = dev->priv;
......@@ -2904,13 +3033,26 @@ static int airo_thread(void *data) {
set_current_state(TASK_INTERRUPTIBLE);
if (ai->flags & JOB_MASK)
break;
if (ai->expires) {
if (time_after_eq(jiffies,ai->expires)){
if (ai->expires || ai->scan_timeout) {
if (ai->scan_timeout &&
time_after_eq(jiffies,ai->scan_timeout)){
set_bit(JOB_SCAN_RESULTS,&ai->flags);
break;
} else if (ai->expires &&
time_after_eq(jiffies,ai->expires)){
set_bit(JOB_AUTOWEP,&ai->flags);
break;
}
if (!signal_pending(current)) {
schedule_timeout(ai->expires - jiffies);
unsigned long wake_at;
if (!ai->expires || !ai->scan_timeout) {
wake_at = max(ai->expires,
ai->scan_timeout);
} else {
wake_at = min(ai->expires,
ai->scan_timeout);
}
schedule_timeout(wake_at - jiffies);
continue;
}
} else if (!signal_pending(current)) {
......@@ -2953,6 +3095,10 @@ static int airo_thread(void *data) {
airo_send_event(dev);
else if (test_bit(JOB_AUTOWEP, &ai->flags))
timer_func(dev);
else if (test_bit(JOB_SCAN_RESULTS, &ai->flags))
airo_process_scan_results(ai);
else /* Shouldn't get here, but we make sure to unlock */
up(&ai->sem);
}
complete_and_exit (&ai->thr_exited, 0);
}
......@@ -3047,19 +3193,15 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
* and reassociations as valid status
* Jean II */
if(newStatus == ASSOCIATED) {
if (apriv->scan_timestamp) {
/* Send an empty event to user space.
* We don't send the received data on
* the event because it would require
* us to do complex transcoding, and
* we want to minimise the work done in
* the irq handler. Use a request to
* extract the data - Jean II */
wrqu.data.length = 0;
wrqu.data.flags = 0;
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
apriv->scan_timestamp = 0;
#if 0
/* FIXME: Grabbing scan results here
* seems to be too early??? Just wait for
* timeout instead. */
if (apriv->scan_timeout > 0) {
set_bit(JOB_SCAN_RESULTS, &apriv->flags);
wake_up_interruptible(&apriv->thr_wait);
}
#endif
if (down_trylock(&apriv->sem) != 0) {
set_bit(JOB_EVENT, &apriv->flags);
wake_up_interruptible(&apriv->thr_wait);
......@@ -3117,8 +3259,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
}
len = le16_to_cpu(hdr.len);
if (len > 2312) {
printk( KERN_ERR "airo: Bad size %d\n", len );
if (len > AIRO_DEF_MTU) {
airo_print_err(apriv->dev->name, "Bad size %d", len);
goto badrx;
}
if (len == 0)
......@@ -3161,10 +3303,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
bap_read (apriv, &gap, sizeof(gap), BAP0);
gap = le16_to_cpu(gap);
if (gap) {
if (gap <= 8)
if (gap <= 8) {
bap_read (apriv, tmpbuf, gap, BAP0);
else
printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n");
} else {
airo_print_err(apriv->dev->name, "gaplen too "
"big. Problems will follow...");
}
}
bap_read (apriv, buffer + hdrlen/2, len, BAP0);
} else {
......@@ -3281,12 +3425,13 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
}
} else {
OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
airo_print_err(apriv->dev->name, "Unallocated FID was "
"used to xmit" );
}
}
exittx:
if ( status & ~STATUS_INTS & ~IGNORE_INTS )
printk( KERN_WARNING "airo: Got weird status %x\n",
airo_print_warn(apriv->dev->name, "Got weird status %x",
status & ~STATUS_INTS & ~IGNORE_INTS );
}
......@@ -3359,8 +3504,8 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
up(&ai->sem);
if (rc)
printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n",
__FUNCTION__,rc);
airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d",
__FUNCTION__, rc);
return rc;
}
......@@ -3489,8 +3634,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
if (ai->wifidev == NULL)
hdr.len = 0;
len = le16_to_cpu(hdr.len);
if (len > 2312) {
printk( KERN_ERR "airo: Bad size %d\n", len );
if (len > AIRO_DEF_MTU) {
airo_print_err(ai->dev->name, "Bad size %d", len);
goto badrx;
}
if (len == 0)
......@@ -3531,8 +3676,8 @@ void mpi_receive_802_11 (struct airo_info *ai)
if (gap <= 8)
ptr += gap;
else
printk(KERN_ERR
"airo: gaplen too big. Problems will follow...\n");
airo_print_err(ai->dev->name,
"gaplen too big. Problems will follow...");
}
memcpy ((char *)buffer + hdrlen, ptr, len);
ptr += len;
......@@ -3604,15 +3749,15 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
if (lock)
up(&ai->sem);
printk(KERN_ERR "airo: Error checking for AUX port\n");
airo_print_err(ai->dev->name, "Error checking for AUX port");
return ERROR;
}
if (!aux_bap || rsp.status & 0xff00) {
ai->bap_read = fast_bap_read;
printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
} else {
ai->bap_read = aux_bap_read;
printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
}
}
if (lock)
......@@ -3643,7 +3788,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
if (cap_rid.softCap & 8)
ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
else
printk(KERN_WARNING "airo: unknown received signal level scale\n");
airo_print_warn(ai->dev->name, "unknown received signal "
"level scale");
}
ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
ai->config.authType = AUTH_OPEN;
......@@ -3706,7 +3852,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
status = enable_MAC(ai, &rsp, lock);
if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x,"
" offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
return ERROR;
}
......@@ -3749,8 +3896,8 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
}
if ( max_tries == -1 ) {
printk( KERN_ERR
"airo: Max tries exceeded when issueing command\n" );
airo_print_err(ai->dev->name,
"Max tries exceeded when issueing command");
if (IN4500(ai, COMMAND) & COMMAND_BUSY)
OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
return ERROR;
......@@ -3762,11 +3909,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
pRsp->rsp1 = IN4500(ai, RESP1);
pRsp->rsp2 = IN4500(ai, RESP2);
if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd);
printk (KERN_ERR "airo: status= %x\n", pRsp->status);
printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0);
printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1);
printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2);
airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
}
// clear stuck command busy if necessary
......@@ -3799,15 +3946,15 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
}
} else if ( status & BAP_ERR ) {
/* invalid rid or offset */
printk( KERN_ERR "airo: BAP error %x %d\n",
airo_print_err(ai->dev->name, "BAP error %x %d",
status, whichbap );
return ERROR;
} else if (status & BAP_DONE) { // success
return SUCCESS;
}
if ( !(max_tries--) ) {
printk( KERN_ERR
"airo: BAP setup error too many retries\n" );
airo_print_err(ai->dev->name,
"airo: BAP setup error too many retries\n");
return ERROR;
}
// -- PC4500 missed it, try again
......@@ -3962,8 +4109,8 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in
len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
if ( len <= 2 ) {
printk( KERN_ERR
"airo: Rid %x has a length of %d which is too short\n",
airo_print_err(ai->dev->name,
"Rid %x has a length of %d which is too short",
(int)rid, (int)len );
rc = ERROR;
goto done;
......@@ -3996,8 +4143,8 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
Resp rsp;
if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
printk(KERN_ERR
"%s: MAC should be disabled (rid=%04x)\n",
airo_print_err(ai->dev->name,
"%s: MAC should be disabled (rid=%04x)",
__FUNCTION__, rid);
memset(&cmd, 0, sizeof(cmd));
memset(&rsp, 0, sizeof(rsp));
......@@ -4013,7 +4160,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
&ai->config_desc.rid_desc, sizeof(Rid));
if (len < 4 || len > 2047) {
printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len);
airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len);
rc = -1;
} else {
memcpy((char *)ai->config_desc.virtual_host_addr,
......@@ -4021,10 +4168,10 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
rc = issuecommand(ai, &cmd, &rsp);
if ((rc & 0xff00) != 0) {
printk(KERN_ERR "%s: Write rid Error %d\n",
__FUNCTION__,rc);
printk(KERN_ERR "%s: Cmd=%04x\n",
__FUNCTION__,cmd.cmd);
airo_print_err(ai->dev->name, "%s: Write rid Error %d",
__FUNCTION__, rc);
airo_print_err(ai->dev->name, "%s: Cmd=%04x",
__FUNCTION__, cmd.cmd);
}
if ((rsp.status & 0x7f00))
......@@ -4123,7 +4270,7 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
len >>= 16;
if (len <= ETH_ALEN * 2) {
printk( KERN_WARNING "Short packet %d\n", len );
airo_print_warn(ai->dev->name, "Short packet %d", len);
return ERROR;
}
len -= ETH_ALEN * 2;
......@@ -4187,7 +4334,7 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket)
}
if (len < hdrlen) {
printk( KERN_WARNING "Short packet %d\n", len );
airo_print_warn(ai->dev->name, "Short packet %d", len);
return ERROR;
}
......@@ -4584,15 +4731,14 @@ static int proc_stats_rid_open( struct inode *inode,
i*4<stats.len; i++){
if (!statsLabels[i]) continue;
if (j+strlen(statsLabels[i])+16>4096) {
printk(KERN_WARNING
"airo: Potentially disasterous buffer overflow averted!\n");
airo_print_warn(apriv->dev->name,
"Potentially disasterous buffer overflow averted!");
break;
}
j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]);
}
if (i*4>=stats.len){
printk(KERN_WARNING
"airo: Got a short rid\n");
airo_print_warn(apriv->dev->name, "Got a short rid");
}
data->readlen = j;
return 0;
......@@ -4754,7 +4900,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
line += 14;
v = get_dec_u16(line, &i, 4);
v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
ai->config.rtsThres = (u16)v;
set_bit (FLAG_COMMIT, &ai->flags);
} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
......@@ -4788,7 +4934,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
line += 15;
v = get_dec_u16(line, &i, 4);
v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
v = v & 0xfffe; /* Make sure its even */
ai->config.fragThresh = (u16)v;
set_bit (FLAG_COMMIT, &ai->flags);
......@@ -4798,8 +4944,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
default:
printk( KERN_WARNING "airo: Unknown modulation\n" );
default: airo_print_warn(ai->dev->name, "Unknown modulation");
}
} else if (!strncmp(line, "Preamble: ", 10)) {
line += 10;
......@@ -4807,10 +4952,10 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
default: printk(KERN_WARNING "airo: Unknown preamble\n");
default: airo_print_warn(ai->dev->name, "Unknown preamble");
}
} else {
printk( KERN_WARNING "Couldn't figure out %s\n", line );
airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
}
while( line[0] && line[0] != '\n' ) line++;
if ( line[0] ) line++;
......@@ -5076,7 +5221,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
}
j = 2;
} else {
printk(KERN_ERR "airo: WepKey passed invalid key index\n");
airo_print_err(ai->dev->name, "WepKey passed invalid key index");
return;
}
......@@ -5489,17 +5634,16 @@ static int __init airo_init_module( void )
airo_entry->gid = proc_gid;
for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
printk( KERN_INFO
"airo: Trying to configure ISA adapter at irq=%d io=0x%x\n",
irq[i], io[i] );
airo_print_info("", "Trying to configure ISA adapter at irq=%d "
"io=0x%x", irq[i], io[i] );
if (init_airo_card( irq[i], io[i], 0, NULL ))
have_isa_dev = 1;
}
#ifdef CONFIG_PCI
printk( KERN_INFO "airo: Probing for PCI adapters\n" );
airo_print_info("", "Probing for PCI adapters");
pci_register_driver(&airo_driver);
printk( KERN_INFO "airo: Finished probing for PCI adapters\n" );
airo_print_info("", "Finished probing for PCI adapters");
#endif
/* Always exit with success, as we are a library module
......@@ -5511,7 +5655,7 @@ static int __init airo_init_module( void )
static void __exit airo_cleanup_module( void )
{
while( airo_devices ) {
printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
airo_print_info(airo_devices->dev->name, "Unregistering...\n");
stop_airo_card( airo_devices->dev, 1 );
}
#ifdef CONFIG_PCI
......@@ -5622,7 +5766,8 @@ static int airo_set_freq(struct net_device *dev,
/* We should do a better check than that,
* based on the card capability !!! */
if((channel < 1) || (channel > 14)) {
printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m);
airo_print_dbg(dev->name, "New channel value of %d is invalid!",
fwrq->m);
rc = -EINVAL;
} else {
readConfigRid(local, 1);
......@@ -5946,8 +6091,8 @@ static int airo_set_rts(struct net_device *dev,
int rthr = vwrq->value;
if(vwrq->disabled)
rthr = 2312;
if((rthr < 0) || (rthr > 2312)) {
rthr = AIRO_DEF_MTU;
if((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
return -EINVAL;
}
readConfigRid(local, 1);
......@@ -5970,7 +6115,7 @@ static int airo_get_rts(struct net_device *dev,
readConfigRid(local, 1);
vwrq->value = local->config.rtsThres;
vwrq->disabled = (vwrq->value >= 2312);
vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
vwrq->fixed = 1;
return 0;
......@@ -5989,8 +6134,8 @@ static int airo_set_frag(struct net_device *dev,
int fthr = vwrq->value;
if(vwrq->disabled)
fthr = 2312;
if((fthr < 256) || (fthr > 2312)) {
fthr = AIRO_DEF_MTU;
if((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
return -EINVAL;
}
fthr &= ~0x1; /* Get an even value - is it really needed ??? */
......@@ -6014,7 +6159,7 @@ static int airo_get_frag(struct net_device *dev,
readConfigRid(local, 1);
vwrq->value = local->config.fragThresh;
vwrq->disabled = (vwrq->value >= 2312);
vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
vwrq->fixed = 1;
return 0;
......@@ -6709,9 +6854,9 @@ static int airo_get_range(struct net_device *dev,
range->throughput = 1500 * 1000;
range->min_rts = 0;
range->max_rts = 2312;
range->max_rts = AIRO_DEF_MTU;
range->min_frag = 256;
range->max_frag = 2312;
range->max_frag = AIRO_DEF_MTU;
if(cap_rid.softCap & 2) {
// WEP: RC4 40 bits
......@@ -6972,6 +7117,7 @@ static int airo_set_scan(struct net_device *dev,
struct airo_info *ai = dev->priv;
Cmd cmd;
Resp rsp;
int wake = 0;
/* Note : you may have realised that, as this is a SET operation,
* this is privileged and therefore a normal user can't
......@@ -6981,17 +7127,25 @@ static int airo_set_scan(struct net_device *dev,
* Jean II */
if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
if (down_interruptible(&ai->sem))
return -ERESTARTSYS;
/* If there's already a scan in progress, don't
* trigger another one. */
if (ai->scan_timeout > 0)
goto out;
/* Initiate a scan command */
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem))
return -ERESTARTSYS;
issuecommand(ai, &cmd, &rsp);
ai->scan_timestamp = jiffies;
up(&ai->sem);
/* At this point, just return to the user. */
ai->scan_timeout = RUN_AT(3*HZ);
wake = 1;
out:
up(&ai->sem);
if (wake)
wake_up_interruptible(&ai->thr_wait);
return 0;
}
......@@ -7111,59 +7265,38 @@ static int airo_get_scan(struct net_device *dev,
char *extra)
{
struct airo_info *ai = dev->priv;
BSSListRid BSSList;
int rc;
BSSListElement *net;
int err = 0;
char *current_ev = extra;
/* When we are associated again, the scan has surely finished.
* Just in case, let's make sure enough time has elapsed since
* we started the scan. - Javier */
if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) {
/* Important note : we don't want to block the caller
* until results are ready for various reasons.
* First, managing wait queues is complex and racy
* (there may be multiple simultaneous callers).
* Second, we grab some rtnetlink lock before comming
* here (in dev_ioctl()).
* Third, the caller can wait on the Wireless Event
* - Jean II */
/* If a scan is in-progress, return -EAGAIN */
if (ai->scan_timeout > 0)
return -EAGAIN;
}
ai->scan_timestamp = 0;
/* There's only a race with proc_BSSList_open(), but its
* consequences are begnign. So I don't bother fixing it - Javier */
/* Try to read the first entry of the scan result */
rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1);
if((rc) || (BSSList.index == 0xffff)) {
/* Client error, no scan results...
* The caller need to restart the scan. */
return -ENODATA;
}
if (down_interruptible(&ai->sem))
return -EAGAIN;
/* Read and parse all entries */
while((!rc) && (BSSList.index != 0xffff)) {
list_for_each_entry (net, &ai->network_list, list) {
/* Translate to WE format this entry */
current_ev = airo_translate_scan(dev, current_ev,
extra + dwrq->length,
&BSSList);
&net->bss);
/* Check if there is space for one more entry */
if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
/* Ask user space to try again with a bigger buffer */
return -E2BIG;
err = -E2BIG;
goto out;
}
/* Read next entry */
rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
&BSSList, sizeof(BSSList), 1);
}
/* Length of data */
dwrq->length = (current_ev - extra);
dwrq->flags = 0; /* todo */
return 0;
out:
up(&ai->sem);
return err;
}
/*------------------------------------------------------------------*/
......@@ -7711,7 +7844,7 @@ static int cmdreset(struct airo_info *ai) {
disable_MAC(ai, 1);
if(!waitbusy (ai)){
printk(KERN_INFO "Waitbusy hang before RESET\n");
airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
return -EBUSY;
}
......@@ -7720,7 +7853,7 @@ static int cmdreset(struct airo_info *ai) {
ssleep(1); /* WAS 600 12/7/00 */
if(!waitbusy (ai)){
printk(KERN_INFO "Waitbusy hang AFTER RESET\n");
airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
return -EBUSY;
}
return 0;
......@@ -7748,7 +7881,7 @@ static int setflashmode (struct airo_info *ai) {
if(!waitbusy(ai)) {
clear_bit (FLAG_FLASHING, &ai->flags);
printk(KERN_INFO "Waitbusy hang after setflash mode\n");
airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
return -EIO;
}
return 0;
......@@ -7777,7 +7910,7 @@ static int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
/* timeout for busy clear wait */
if(waittime <= 0 ){
printk(KERN_INFO "flash putchar busywait timeout! \n");
airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
return -EBUSY;
}
......@@ -7866,7 +7999,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev){
if (!test_bit(FLAG_MPI,&ai->flags))
for( i = 0; i < MAX_FIDS; i++ ) {
ai->fids[i] = transmit_allocate
( ai, 2312, i >= MAX_FIDS / 2 );
( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 );
}
ssleep(1); /* Added 12/7/00 */
......
......@@ -3141,7 +3141,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
if (ret == 1) {
sta = ap_add_sta(ap, sta_addr);
if (!sta)
ret = -1;
return -1;
sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
sta->ap = 1;
memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
......
......@@ -585,8 +585,6 @@ static int prism2_config(dev_link_t *link)
parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL);
if (parse == NULL || hw_priv == NULL) {
kfree(parse);
kfree(hw_priv);
ret = -ENOMEM;
goto failed;
}
......
......@@ -928,15 +928,15 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
up(&local->rid_bap_sem);
if (res) {
printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
"failed (res=%d, rid=%04x, len=%d)\n",
dev->name, res, rid, len);
return res;
}
if (res == -ETIMEDOUT)
prism2_hw_reset(dev);
if (res == -ETIMEDOUT)
prism2_hw_reset(dev);
}
return res;
}
......
......@@ -3358,10 +3358,6 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
if (!sta_ptr)
local->tx_keyidx = i;
else if (i) {
ret = -EINVAL;
goto done;
}
}
......
......@@ -307,7 +307,7 @@ static int prism2_pci_probe(struct pci_dev *pdev,
memset(hw_priv, 0, sizeof(*hw_priv));
if (pci_enable_device(pdev))
return -EIO;
goto err_out_free;
phymem = pci_resource_start(pdev, 0);
......@@ -368,6 +368,8 @@ static int prism2_pci_probe(struct pci_dev *pdev,
err_out_disable:
pci_disable_device(pdev);
prism2_free_local_data(dev);
err_out_free:
kfree(hw_priv);
return -ENODEV;
......
......@@ -368,7 +368,7 @@ static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
switch (cis[pos]) {
case CISTPL_CONFIG:
if (cis[pos + 1] < 1)
if (cis[pos + 1] < 2)
goto cis_error;
rmsz = (cis[pos + 2] & 0x3c) >> 2;
rasz = cis[pos + 2] & 0x03;
......@@ -390,7 +390,7 @@ static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
break;
case CISTPL_MANFID:
if (cis[pos + 1] < 4)
if (cis[pos + 1] < 5)
goto cis_error;
manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
......@@ -452,7 +452,7 @@ static int prism2_plx_probe(struct pci_dev *pdev,
memset(hw_priv, 0, sizeof(*hw_priv));
if (pci_enable_device(pdev))
return -EIO;
goto err_out_free;
/* National Datacomm NCP130 based on TMD7160, not PLX9052. */
tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
......@@ -567,9 +567,6 @@ static int prism2_plx_probe(struct pci_dev *pdev,
return hostap_hw_ready(dev);
fail:
prism2_free_local_data(dev);
kfree(hw_priv);
if (irq_registered && dev)
free_irq(dev->irq, dev);
......@@ -577,6 +574,10 @@ static int prism2_plx_probe(struct pci_dev *pdev,
iounmap(attr_mem);
pci_disable_device(pdev);
prism2_free_local_data(dev);
err_out_free:
kfree(hw_priv);
return -ENODEV;
}
......
/*
* This file define a set of standard wireless extensions
*
* Version : 19 18.3.05
* Version : 20 17.2.06
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
* Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
*/
#ifndef _LINUX_WIRELESS_H
......@@ -80,7 +80,7 @@
* (there is some stuff that will be added in the future...)
* I just plan to increment with each new version.
*/
#define WIRELESS_EXT 19
#define WIRELESS_EXT 20
/*
* Changes :
......@@ -204,6 +204,10 @@
* - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
* - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
* - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
*
* V19 to V20
* ----------
* - RtNetlink requests support (SET/GET)
*/
/**************************** CONSTANTS ****************************/
......
......@@ -4,7 +4,7 @@
* Version : 7 18.3.05
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 2001-2005 Jean Tourrilhes, All Rights Reserved.
* Copyright (c) 2001-2006 Jean Tourrilhes, All Rights Reserved.
*/
#ifndef _IW_HANDLER_H
......@@ -436,6 +436,16 @@ extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
/* Handle IOCTLs, called in net/core/dev.c */
extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
/* Handle RtNetlink requests, called in net/core/rtnetlink.c */
extern int wireless_rtnetlink_set(struct net_device * dev,
char * data,
int len);
extern int wireless_rtnetlink_get(struct net_device * dev,
char * data,
int len,
char ** p_buf,
int * p_len);
/* Second : functions that may be called by driver modules */
/* Send a single event to user space */
......
......@@ -51,6 +51,10 @@
#include <net/sock.h>
#include <net/pkt_sched.h>
#include <net/netlink.h>
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
#include <linux/wireless.h>
#include <net/iw_handler.h>
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
static DEFINE_MUTEX(rtnl_mutex);
......@@ -467,6 +471,17 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
goto out;
}
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
if (ida[IFLA_WIRELESS - 1]) {
/* Call Wireless Extensions.
* Various stuff checked in there... */
err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
if (err)
goto out;
}
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
err = 0;
out:
......@@ -477,6 +492,83 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
return err;
}
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg)
{
struct ifinfomsg *ifm = NLMSG_DATA(in_nlh);
struct rtattr **ida = arg;
struct net_device *dev;
struct ifinfomsg *r;
struct nlmsghdr *nlh;
int err = -ENOBUFS;
struct sk_buff *skb;
unsigned char *b;
char *iw_buf = NULL;
int iw_buf_len = 0;
if (ifm->ifi_index >= 0)
dev = dev_get_by_index(ifm->ifi_index);
else
return -EINVAL;
if (!dev)
return -ENODEV;
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
if (ida[IFLA_WIRELESS - 1]) {
/* Call Wireless Extensions. We need to know the size before
* we can alloc. Various stuff checked in there... */
err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len);
if (err)
goto out;
}
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
/* Create a skb big enough to include all the data.
* Some requests are way bigger than 4k... Jean II */
skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)),
GFP_KERNEL);
if (!skb)
goto out;
b = skb->tail;
/* Put in the message the usual good stuff */
nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq,
RTM_NEWLINK, sizeof(*r));
r = NLMSG_DATA(nlh);
r->ifi_family = AF_UNSPEC;
r->__ifi_pad = 0;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
r->ifi_flags = dev->flags;
r->ifi_change = 0;
/* Put the wireless payload if it exist */
if(iw_buf != NULL)
RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len,
iw_buf + IW_EV_POINT_OFF);
nlh->nlmsg_len = skb->tail - b;
/* Needed ? */
NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
if (err > 0)
err = 0;
out:
if(iw_buf != NULL)
kfree(iw_buf);
dev_put(dev);
return err;
rtattr_failure:
nlmsg_failure:
kfree_skb(skb);
goto out;
}
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
{
int idx;
......@@ -642,7 +734,11 @@ static void rtnetlink_rcv(struct sock *sk, int len)
static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
{
[RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },
[RTM_GETLINK - RTM_BASE] = {
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
.doit = do_getlink,
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
.dumpit = rtnetlink_dump_ifinfo },
[RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
[RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
[RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
......
......@@ -2,7 +2,7 @@
* This file implement the Wireless Extensions APIs.
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
* Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
*
* (As all part of the Linux kernel, this file is GPL)
*/
......@@ -65,6 +65,9 @@
* o Start deprecating dev->get_wireless_stats, output a warning
* o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
* o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
*
* v8 - 17.02.06 - Jean II
* o RtNetlink requests support (SET/GET)
*/
/***************************** INCLUDES *****************************/
......@@ -89,11 +92,13 @@
/* Debugging stuff */
#undef WE_IOCTL_DEBUG /* Debug IOCTL API */
#undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */
#undef WE_EVENT_DEBUG /* Debug Event dispatcher */
#undef WE_SPY_DEBUG /* Debug enhanced spy support */
/* Options */
#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */
//CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */
#define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */
#define WE_SET_EVENT /* Generate an event on some set commands */
/************************* GLOBAL VARIABLES *************************/
......@@ -156,13 +161,18 @@ static const struct iw_ioctl_description standard_ioctl[] = {
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
.header_type = IW_HEADER_TYPE_NULL,
.header_type = IW_HEADER_TYPE_POINT,
.token_size = sizeof(struct iw_priv_args),
.max_tokens = 16,
.flags = IW_DESCR_FLAG_NOMAX,
},
[SIOCSIWSTATS - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_NULL,
},
[SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
.header_type = IW_HEADER_TYPE_NULL,
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
.max_tokens = sizeof(struct iw_statistics),
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWSPY - SIOCIWFIRST] = {
......@@ -529,6 +539,70 @@ static inline int adjust_priv_size(__u16 args,
return num * iw_priv_type_size[type];
}
/* ---------------------------------------------------------------- */
/*
* Standard Wireless Handler : get wireless stats
* Allow programatic access to /proc/net/wireless even if /proc
* doesn't exist... Also more efficient...
*/
static int iw_handler_get_iwstats(struct net_device * dev,
struct iw_request_info * info,
union iwreq_data * wrqu,
char * extra)
{
/* Get stats from the driver */
struct iw_statistics *stats;
stats = get_wireless_stats(dev);
if (stats != (struct iw_statistics *) NULL) {
/* Copy statistics to extra */
memcpy(extra, stats, sizeof(struct iw_statistics));
wrqu->data.length = sizeof(struct iw_statistics);
/* Check if we need to clear the updated flag */
if(wrqu->data.flags != 0)
stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
return 0;
} else
return -EOPNOTSUPP;
}
/* ---------------------------------------------------------------- */
/*
* Standard Wireless Handler : get iwpriv definitions
* Export the driver private handler definition
* They will be picked up by tools like iwpriv...
*/
static int iw_handler_get_private(struct net_device * dev,
struct iw_request_info * info,
union iwreq_data * wrqu,
char * extra)
{
/* Check if the driver has something to export */
if((dev->wireless_handlers->num_private_args == 0) ||
(dev->wireless_handlers->private_args == NULL))
return -EOPNOTSUPP;
/* Check if there is enough buffer up there */
if(wrqu->data.length < dev->wireless_handlers->num_private_args) {
/* User space can't know in advance how large the buffer
* needs to be. Give it a hint, so that we can support
* any size buffer we want somewhat efficiently... */
wrqu->data.length = dev->wireless_handlers->num_private_args;
return -E2BIG;
}
/* Set the number of available ioctls. */
wrqu->data.length = dev->wireless_handlers->num_private_args;
/* Copy structure to the user buffer. */
memcpy(extra, dev->wireless_handlers->private_args,
sizeof(struct iw_priv_args) * wrqu->data.length);
return 0;
}
/******************** /proc/net/wireless SUPPORT ********************/
/*
......@@ -628,83 +702,16 @@ int __init wireless_proc_init(void)
* or just call the driver ioctl handler.
*/
/* ---------------------------------------------------------------- */
/*
* Allow programatic access to /proc/net/wireless even if /proc
* doesn't exist... Also more efficient...
*/
static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
{
/* Get stats from the driver */
struct iw_statistics *stats;
stats = get_wireless_stats(dev);
if (stats != (struct iw_statistics *) NULL) {
struct iwreq * wrq = (struct iwreq *)ifr;
/* Copy statistics to the user buffer */
if(copy_to_user(wrq->u.data.pointer, stats,
sizeof(struct iw_statistics)))
return -EFAULT;
/* Check if we need to clear the updated flag */
if(wrq->u.data.flags != 0)
stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
return 0;
} else
return -EOPNOTSUPP;
}
/* ---------------------------------------------------------------- */
/*
* Export the driver private handler definition
* They will be picked up by tools like iwpriv...
*/
static inline int ioctl_export_private(struct net_device * dev,
struct ifreq * ifr)
{
struct iwreq * iwr = (struct iwreq *) ifr;
/* Check if the driver has something to export */
if((dev->wireless_handlers->num_private_args == 0) ||
(dev->wireless_handlers->private_args == NULL))
return -EOPNOTSUPP;
/* Check NULL pointer */
if(iwr->u.data.pointer == NULL)
return -EFAULT;
/* Check if there is enough buffer up there */
if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
/* User space can't know in advance how large the buffer
* needs to be. Give it a hint, so that we can support
* any size buffer we want somewhat efficiently... */
iwr->u.data.length = dev->wireless_handlers->num_private_args;
return -E2BIG;
}
/* Set the number of available ioctls. */
iwr->u.data.length = dev->wireless_handlers->num_private_args;
/* Copy structure to the user buffer. */
if (copy_to_user(iwr->u.data.pointer,
dev->wireless_handlers->private_args,
sizeof(struct iw_priv_args) * iwr->u.data.length))
return -EFAULT;
return 0;
}
/* ---------------------------------------------------------------- */
/*
* Wrapper to call a standard Wireless Extension handler.
* We do various checks and also take care of moving data between
* user space and kernel space.
*/
static inline int ioctl_standard_call(struct net_device * dev,
struct ifreq * ifr,
unsigned int cmd,
iw_handler handler)
static int ioctl_standard_call(struct net_device * dev,
struct ifreq * ifr,
unsigned int cmd,
iw_handler handler)
{
struct iwreq * iwr = (struct iwreq *) ifr;
const struct iw_ioctl_description * descr;
......@@ -1048,14 +1055,20 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
{
case SIOCGIWSTATS:
/* Get Wireless Stats */
return dev_iwstats(dev, ifr);
return ioctl_standard_call(dev,
ifr,
cmd,
&iw_handler_get_iwstats);
case SIOCGIWPRIV:
/* Check if we have some wireless handlers defined */
if(dev->wireless_handlers != NULL) {
/* We export to user space the definition of
* the private handler ourselves */
return ioctl_export_private(dev, ifr);
return ioctl_standard_call(dev,
ifr,
cmd,
&iw_handler_get_private);
}
// ## Fall-through for old API ##
default:
......@@ -1088,16 +1101,739 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
return -EINVAL;
}
/********************** RTNETLINK REQUEST API **********************/
/*
* The alternate user space API to configure all those Wireless Extensions
* is through RtNetlink.
* This API support only the new driver API (iw_handler).
*
* This RtNetlink API use the same query/reply model as the ioctl API.
* Maximum effort has been done to fit in the RtNetlink model, and
* we support both RtNetlink Set and RtNelink Get operations.
* On the other hand, we don't offer Dump operations because of the
* following reasons :
* o Large number of parameters, most optional
* o Large size of some parameters (> 100 bytes)
* o Each parameters need to be extracted from hardware
* o Scan requests can take seconds and disable network activity.
* Because of this high cost/overhead, we want to return only the
* parameters the user application is really interested in.
* We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag.
*
* The API uses the standard RtNetlink socket. When the RtNetlink code
* find a IFLA_WIRELESS field in a RtNetlink SET_LINK request,
* it calls here.
*/
#ifdef CONFIG_NET_WIRELESS_RTNETLINK
/* ---------------------------------------------------------------- */
/*
* Wrapper to call a standard Wireless Extension GET handler.
* We do various checks and call the handler with the proper args.
*/
static int rtnetlink_standard_get(struct net_device * dev,
struct iw_event * request,
int request_len,
iw_handler handler,
char ** p_buf,
int * p_len)
{
const struct iw_ioctl_description * descr = NULL;
unsigned int cmd;
union iwreq_data * wrqu;
int hdr_len;
struct iw_request_info info;
char * buffer = NULL;
int buffer_size = 0;
int ret = -EINVAL;
/* Get the description of the Request */
cmd = request->cmd;
if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
return -EOPNOTSUPP;
descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
dev->name, cmd);
printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
#endif /* WE_RTNETLINK_DEBUG */
/* Check if wrqu is complete */
hdr_len = event_type_size[descr->header_type];
if(request_len < hdr_len) {
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG
"%s (WE.r) : Wireless request too short (%d)\n",
dev->name, request_len);
#endif /* WE_RTNETLINK_DEBUG */
return -EINVAL;
}
/* Prepare the call */
info.cmd = cmd;
info.flags = 0;
/* Check if we have extra data in the reply or not */
if(descr->header_type != IW_HEADER_TYPE_POINT) {
/* Create the kernel buffer that we will return.
* It's at an offset to match the TYPE_POINT case... */
buffer_size = request_len + IW_EV_POINT_OFF;
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (buffer == NULL) {
return -ENOMEM;
}
/* Copy event data */
memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
/* Use our own copy of wrqu */
wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
+ IW_EV_LCP_LEN);
/* No extra arguments. Trivial to handle */
ret = handler(dev, &info, wrqu, NULL);
} else {
union iwreq_data wrqu_point;
char * extra = NULL;
int extra_size = 0;
/* Get a temp copy of wrqu (skip pointer) */
memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
((char *) request) + IW_EV_LCP_LEN,
IW_EV_POINT_LEN - IW_EV_LCP_LEN);
/* Calculate space needed by arguments. Always allocate
* for max space. Easier, and won't last long... */
extra_size = descr->max_tokens * descr->token_size;
/* Support for very large requests */
if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
(wrqu_point.data.length > descr->max_tokens))
extra_size = (wrqu_point.data.length
* descr->token_size);
buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
dev->name, extra_size, buffer_size);
#endif /* WE_RTNETLINK_DEBUG */
/* Create the kernel buffer that we will return */
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (buffer == NULL) {
return -ENOMEM;
}
/* Put wrqu in the right place (just before extra).
* Leave space for IWE header and dummy pointer...
* Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
*/
memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
((char *) &wrqu_point) + IW_EV_POINT_OFF,
IW_EV_POINT_LEN - IW_EV_LCP_LEN);
wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
/* Extra comes logically after that. Offset +12 bytes. */
extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
/* Call the handler */
ret = handler(dev, &info, wrqu, extra);
/* Calculate real returned length */
extra_size = (wrqu->data.length * descr->token_size);
/* Re-adjust reply size */
request->len = extra_size + IW_EV_POINT_LEN;
/* Put the iwe header where it should, i.e. scrap the
* dummy pointer. */
memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
#endif /* WE_RTNETLINK_DEBUG */
/* Check if there is enough buffer up there */
if(wrqu_point.data.length < wrqu->data.length)
ret = -E2BIG;
}
/* Return the buffer to the caller */
if (!ret) {
*p_buf = buffer;
*p_len = request->len;
} else {
/* Cleanup */
if(buffer)
kfree(buffer);
}
return ret;
}
/* ---------------------------------------------------------------- */
/*
* Wrapper to call a standard Wireless Extension SET handler.
* We do various checks and call the handler with the proper args.
*/
static inline int rtnetlink_standard_set(struct net_device * dev,
struct iw_event * request,
int request_len,
iw_handler handler)
{
const struct iw_ioctl_description * descr = NULL;
unsigned int cmd;
union iwreq_data * wrqu;
union iwreq_data wrqu_point;
int hdr_len;
char * extra = NULL;
int extra_size = 0;
struct iw_request_info info;
int ret = -EINVAL;
/* Get the description of the Request */
cmd = request->cmd;
if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
return -EOPNOTSUPP;
descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
dev->name, cmd);
printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
#endif /* WE_RTNETLINK_DEBUG */
/* Extract fixed header from request. This is properly aligned. */
wrqu = &request->u;
/* Check if wrqu is complete */
hdr_len = event_type_size[descr->header_type];
if(request_len < hdr_len) {
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG
"%s (WE.r) : Wireless request too short (%d)\n",
dev->name, request_len);
#endif /* WE_RTNETLINK_DEBUG */
return -EINVAL;
}
/* Prepare the call */
info.cmd = cmd;
info.flags = 0;
/* Check if we have extra data in the request or not */
if(descr->header_type != IW_HEADER_TYPE_POINT) {
/* No extra arguments. Trivial to handle */
ret = handler(dev, &info, wrqu, NULL);
} else {
int extra_len;
/* Put wrqu in the right place (skip pointer) */
memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
/* Don't forget about the event code... */
wrqu = &wrqu_point;
/* Check if number of token fits within bounds */
if(wrqu_point.data.length > descr->max_tokens)
return -E2BIG;
if(wrqu_point.data.length < descr->min_tokens)
return -EINVAL;
/* Real length of payload */
extra_len = wrqu_point.data.length * descr->token_size;
/* Check if request is self consistent */
if((request_len - hdr_len) < extra_len) {
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
dev->name, extra_size);
#endif /* WE_RTNETLINK_DEBUG */
return -EINVAL;
}
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
dev->name, extra_size);
#endif /* WE_RTNETLINK_DEBUG */
/* Always allocate for max space. Easier, and won't last
* long... */
extra_size = descr->max_tokens * descr->token_size;
extra = kmalloc(extra_size, GFP_KERNEL);
if (extra == NULL)
return -ENOMEM;
/* Copy extra in aligned buffer */
memcpy(extra, ((char *) request) + hdr_len, extra_len);
/* Call the handler */
ret = handler(dev, &info, &wrqu_point, extra);
}
#ifdef WE_SET_EVENT
/* Generate an event to notify listeners of the change */
if((descr->flags & IW_DESCR_FLAG_EVENT) &&
((ret == 0) || (ret == -EIWCOMMIT))) {
if(descr->flags & IW_DESCR_FLAG_RESTRICT)
/* If the event is restricted, don't
* export the payload */
wireless_send_event(dev, cmd, wrqu, NULL);
else
wireless_send_event(dev, cmd, wrqu, extra);
}
#endif /* WE_SET_EVENT */
/* Cleanup - I told you it wasn't that long ;-) */
if(extra)
kfree(extra);
/* Call commit handler if needed and defined */
if(ret == -EIWCOMMIT)
ret = call_commit_handler(dev);
return ret;
}
/* ---------------------------------------------------------------- */
/*
* Wrapper to call a private Wireless Extension GET handler.
* Same as above...
* It's not as nice and slimline as the standard wrapper. The cause
* is struct iw_priv_args, which was not really designed for the
* job we are going here.
*
* IMPORTANT : This function prevent to set and get data on the same
* IOCTL and enforce the SET/GET convention. Not doing it would be
* far too hairy...
* If you need to set and get data at the same time, please don't use
* a iw_handler but process it in your ioctl handler (i.e. use the
* old driver API).
*/
static inline int rtnetlink_private_get(struct net_device * dev,
struct iw_event * request,
int request_len,
iw_handler handler,
char ** p_buf,
int * p_len)
{
const struct iw_priv_args * descr = NULL;
unsigned int cmd;
union iwreq_data * wrqu;
int hdr_len;
struct iw_request_info info;
int extra_size = 0;
int i;
char * buffer = NULL;
int buffer_size = 0;
int ret = -EINVAL;
/* Get the description of the Request */
cmd = request->cmd;
for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
if(cmd == dev->wireless_handlers->private_args[i].cmd) {
descr = &(dev->wireless_handlers->private_args[i]);
break;
}
if(descr == NULL)
return -EOPNOTSUPP;
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
dev->name, cmd);
printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
dev->name, descr->name, descr->set_args, descr->get_args);
#endif /* WE_RTNETLINK_DEBUG */
/* Compute the max size of the get arguments */
extra_size = get_priv_size(descr->get_args);
/* Does it fits in wrqu ? */
if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
(extra_size <= IFNAMSIZ)) {
hdr_len = extra_size;
extra_size = 0;
} else {
hdr_len = IW_EV_POINT_LEN;
}
/* Check if wrqu is complete */
if(request_len < hdr_len) {
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG
"%s (WE.r) : Wireless request too short (%d)\n",
dev->name, request_len);
#endif /* WE_RTNETLINK_DEBUG */
return -EINVAL;
}
/* Prepare the call */
info.cmd = cmd;
info.flags = 0;
/* Check if we have a pointer to user space data or not. */
if(extra_size == 0) {
/* Create the kernel buffer that we will return.
* It's at an offset to match the TYPE_POINT case... */
buffer_size = request_len + IW_EV_POINT_OFF;
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (buffer == NULL) {
return -ENOMEM;
}
/* Copy event data */
memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
/* Use our own copy of wrqu */
wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
+ IW_EV_LCP_LEN);
/* No extra arguments. Trivial to handle */
ret = handler(dev, &info, wrqu, (char *) wrqu);
} else {
char * extra;
/* Buffer for full reply */
buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
dev->name, extra_size, buffer_size);
#endif /* WE_RTNETLINK_DEBUG */
/* Create the kernel buffer that we will return */
buffer = kmalloc(buffer_size, GFP_KERNEL);
if (buffer == NULL) {
return -ENOMEM;
}
/* Put wrqu in the right place (just before extra).
* Leave space for IWE header and dummy pointer...
* Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
*/
memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
((char *) request) + IW_EV_LCP_LEN,
IW_EV_POINT_LEN - IW_EV_LCP_LEN);
wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
/* Extra comes logically after that. Offset +12 bytes. */
extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
/* Call the handler */
ret = handler(dev, &info, wrqu, extra);
/* Adjust for the actual length if it's variable,
* avoid leaking kernel bits outside. */
if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
extra_size = adjust_priv_size(descr->get_args, wrqu);
/* Re-adjust reply size */
request->len = extra_size + IW_EV_POINT_LEN;
/* Put the iwe header where it should, i.e. scrap the
* dummy pointer. */
memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
#endif /* WE_RTNETLINK_DEBUG */
}
/* Return the buffer to the caller */
if (!ret) {
*p_buf = buffer;
*p_len = request->len;
} else {
/* Cleanup */
if(buffer)
kfree(buffer);
}
return ret;
}
/* ---------------------------------------------------------------- */
/*
* Wrapper to call a private Wireless Extension SET handler.
* Same as above...
* It's not as nice and slimline as the standard wrapper. The cause
* is struct iw_priv_args, which was not really designed for the
* job we are going here.
*
* IMPORTANT : This function prevent to set and get data on the same
* IOCTL and enforce the SET/GET convention. Not doing it would be
* far too hairy...
* If you need to set and get data at the same time, please don't use
* a iw_handler but process it in your ioctl handler (i.e. use the
* old driver API).
*/
static inline int rtnetlink_private_set(struct net_device * dev,
struct iw_event * request,
int request_len,
iw_handler handler)
{
const struct iw_priv_args * descr = NULL;
unsigned int cmd;
union iwreq_data * wrqu;
union iwreq_data wrqu_point;
int hdr_len;
char * extra = NULL;
int extra_size = 0;
int offset = 0; /* For sub-ioctls */
struct iw_request_info info;
int i;
int ret = -EINVAL;
/* Get the description of the Request */
cmd = request->cmd;
for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
if(cmd == dev->wireless_handlers->private_args[i].cmd) {
descr = &(dev->wireless_handlers->private_args[i]);
break;
}
if(descr == NULL)
return -EOPNOTSUPP;
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
ifr->ifr_name, cmd);
printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
dev->name, descr->name, descr->set_args, descr->get_args);
#endif /* WE_RTNETLINK_DEBUG */
/* Compute the size of the set arguments */
/* Check for sub-ioctl handler */
if(descr->name[0] == '\0')
/* Reserve one int for sub-ioctl index */
offset = sizeof(__u32);
/* Size of set arguments */
extra_size = get_priv_size(descr->set_args);
/* Does it fits in wrqu ? */
if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
(extra_size <= IFNAMSIZ)) {
hdr_len = IW_EV_LCP_LEN + extra_size;
extra_size = 0;
} else {
hdr_len = IW_EV_POINT_LEN;
}
/* Extract fixed header from request. This is properly aligned. */
wrqu = &request->u;
/* Check if wrqu is complete */
if(request_len < hdr_len) {
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG
"%s (WE.r) : Wireless request too short (%d)\n",
dev->name, request_len);
#endif /* WE_RTNETLINK_DEBUG */
return -EINVAL;
}
/* Prepare the call */
info.cmd = cmd;
info.flags = 0;
/* Check if we have a pointer to user space data or not. */
if(extra_size == 0) {
/* No extra arguments. Trivial to handle */
ret = handler(dev, &info, wrqu, (char *) wrqu);
} else {
int extra_len;
/* Put wrqu in the right place (skip pointer) */
memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
/* Does it fits within bounds ? */
if(wrqu_point.data.length > (descr->set_args &
IW_PRIV_SIZE_MASK))
return -E2BIG;
/* Real length of payload */
extra_len = adjust_priv_size(descr->set_args, &wrqu_point);
/* Check if request is self consistent */
if((request_len - hdr_len) < extra_len) {
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
dev->name, extra_size);
#endif /* WE_RTNETLINK_DEBUG */
return -EINVAL;
}
#ifdef WE_RTNETLINK_DEBUG
printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
dev->name, extra_size);
#endif /* WE_RTNETLINK_DEBUG */
/* Always allocate for max space. Easier, and won't last
* long... */
extra = kmalloc(extra_size, GFP_KERNEL);
if (extra == NULL)
return -ENOMEM;
/* Copy extra in aligned buffer */
memcpy(extra, ((char *) request) + hdr_len, extra_len);
/* Call the handler */
ret = handler(dev, &info, &wrqu_point, extra);
/* Cleanup - I told you it wasn't that long ;-) */
kfree(extra);
}
/* Call commit handler if needed and defined */
if(ret == -EIWCOMMIT)
ret = call_commit_handler(dev);
return ret;
}
/* ---------------------------------------------------------------- */
/*
* Main RtNetlink dispatcher. Called from the main networking code
* (do_getlink() in net/core/rtnetlink.c).
* Check the type of Request and call the appropriate wrapper...
*/
int wireless_rtnetlink_get(struct net_device * dev,
char * data,
int len,
char ** p_buf,
int * p_len)
{
struct iw_event * request = (struct iw_event *) data;
iw_handler handler;
/* Check length */
if(len < IW_EV_LCP_LEN) {
printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
dev->name, len);
return -EINVAL;
}
/* ReCheck length (len may have padding) */
if(request->len > len) {
printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
dev->name, request->len, len);
return -EINVAL;
}
/* Only accept GET requests in here */
if(!IW_IS_GET(request->cmd))
return -EOPNOTSUPP;
/* Special cases */
if(request->cmd == SIOCGIWSTATS)
/* Get Wireless Stats */
return rtnetlink_standard_get(dev,
request,
request->len,
&iw_handler_get_iwstats,
p_buf, p_len);
if(request->cmd == SIOCGIWPRIV) {
/* Check if we have some wireless handlers defined */
if(dev->wireless_handlers == NULL)
return -EOPNOTSUPP;
/* Get Wireless Stats */
return rtnetlink_standard_get(dev,
request,
request->len,
&iw_handler_get_private,
p_buf, p_len);
}
/* Basic check */
if (!netif_device_present(dev))
return -ENODEV;
/* Try to find the handler */
handler = get_handler(dev, request->cmd);
if(handler != NULL) {
/* Standard and private are not the same */
if(request->cmd < SIOCIWFIRSTPRIV)
return rtnetlink_standard_get(dev,
request,
request->len,
handler,
p_buf, p_len);
else
return rtnetlink_private_get(dev,
request,
request->len,
handler,
p_buf, p_len);
}
return -EOPNOTSUPP;
}
/* ---------------------------------------------------------------- */
/*
* Main RtNetlink dispatcher. Called from the main networking code
* (do_setlink() in net/core/rtnetlink.c).
* Check the type of Request and call the appropriate wrapper...
*/
int wireless_rtnetlink_set(struct net_device * dev,
char * data,
int len)
{
struct iw_event * request = (struct iw_event *) data;
iw_handler handler;
/* Check length */
if(len < IW_EV_LCP_LEN) {
printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
dev->name, len);
return -EINVAL;
}
/* ReCheck length (len may have padding) */
if(request->len > len) {
printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
dev->name, request->len, len);
return -EINVAL;
}
/* Only accept SET requests in here */
if(!IW_IS_SET(request->cmd))
return -EOPNOTSUPP;
/* Basic check */
if (!netif_device_present(dev))
return -ENODEV;
/* New driver API : try to find the handler */
handler = get_handler(dev, request->cmd);
if(handler != NULL) {
/* Standard and private are not the same */
if(request->cmd < SIOCIWFIRSTPRIV)
return rtnetlink_standard_set(dev,
request,
request->len,
handler);
else
return rtnetlink_private_set(dev,
request,
request->len,
handler);
}
return -EOPNOTSUPP;
}
#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
/************************* EVENT PROCESSING *************************/
/*
* Process events generated by the wireless layer or the driver.
* Most often, the event will be propagated through rtnetlink
*/
#ifdef WE_EVENT_NETLINK
/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
* It is declared in <linux/rtnetlink.h> */
#ifdef WE_EVENT_RTNETLINK
/* ---------------------------------------------------------------- */
/*
* Fill a rtnetlink message with our event data.
......@@ -1121,12 +1857,11 @@ static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
r->__ifi_pad = 0;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
r->ifi_flags = dev->flags;
r->ifi_flags = dev_get_flags(dev);
r->ifi_change = 0; /* Wireless changes don't affect those flags */
/* Add the wireless events in the netlink packet */
RTA_PUT(skb, IFLA_WIRELESS,
event_len, event);
RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
nlh->nlmsg_len = skb->tail - b;
return skb->len;
......@@ -1163,7 +1898,7 @@ static inline void rtmsg_iwinfo(struct net_device * dev,
NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
}
#endif /* WE_EVENT_NETLINK */
#endif /* WE_EVENT_RTNETLINK */
/* ---------------------------------------------------------------- */
/*
......@@ -1255,10 +1990,10 @@ void wireless_send_event(struct net_device * dev,
if(extra != NULL)
memcpy(((char *) event) + hdr_len, extra, extra_len);
#ifdef WE_EVENT_NETLINK
/* rtnetlink event channel */
#ifdef WE_EVENT_RTNETLINK
/* Send via the RtNetlink event channel */
rtmsg_iwinfo(dev, (char *) event, event_len);
#endif /* WE_EVENT_NETLINK */
#endif /* WE_EVENT_RTNETLINK */
/* Cleanup */
kfree(event);
......
......@@ -38,7 +38,7 @@ static void
ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
{
unsigned long flags;
function_enter();
/* Switch to correct channel for this network */
mac->set_channel(mac->dev, net->channel);
......@@ -64,8 +64,6 @@ ieee80211softmac_assoc_timeout(void *d)
struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
unsigned long flags;
function_enter();
spin_lock_irqsave(&mac->lock, flags);
/* we might race against ieee80211softmac_handle_assoc_response,
* so make sure only one of us does something */
......@@ -89,7 +87,6 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
{
unsigned long flags;
struct ieee80211softmac_network *found;
function_enter();
if (mac->associnfo.bssvalid && mac->associated) {
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
......@@ -173,8 +170,6 @@ ieee80211softmac_assoc_work(void *d)
struct ieee80211_network *net = NULL, *best = NULL;
unsigned long flags;
function_enter();
/* meh */
if (mac->associated)
ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
......@@ -391,8 +386,6 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev,
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct ieee80211softmac_network *network;
function_enter();
network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
if (!network) {
dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
......
......@@ -36,8 +36,6 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
struct ieee80211softmac_auth_queue_item *auth;
unsigned long flags;
function_enter();
if (net->authenticating)
return 0;
......@@ -78,8 +76,6 @@ ieee80211softmac_auth_queue(void *data)
struct ieee80211softmac_network *net;
unsigned long flags;
function_enter();
auth = (struct ieee80211softmac_auth_queue_item *)data;
net = auth->net;
mac = auth->mac;
......@@ -128,8 +124,6 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
unsigned long flags;
u8 * data;
function_enter();
/* Find correct auth queue item */
spin_lock_irqsave(&mac->lock, flags);
list_for_each(list_ptr, &mac->auth_queue) {
......@@ -277,8 +271,6 @@ ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
struct list_head *list_ptr;
unsigned long flags;
function_enter();
/* Lock and reset status flags */
spin_lock_irqsave(&mac->lock, flags);
net->authenticating = 0;
......@@ -320,8 +312,6 @@ ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
{
int ret;
function_enter();
/* Make sure the network is authenticated */
if (!net->authenticated)
{
......@@ -348,8 +338,6 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de
struct ieee80211softmac_network *net = NULL;
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
function_enter();
if (!deauth) {
dprintk("deauth without deauth packet. eek!\n");
return 0;
......
......@@ -75,15 +75,6 @@
# define dprintk(f, x...) do { /* nothing */ } while (0)
#endif
#ifdef function_enter
# undef function_enter
#endif
#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
# define function_enter() do { printk(KERN_DEBUG PFX "%s:%d:%s()\n", __FILE__, __LINE__, __FUNCTION__); } while (0)
#else
# define function_enter() do { /* nothing */ } while (0)
#endif
/* private definitions and prototypes */
/*** prototypes from _scan.c */
......
......@@ -232,6 +232,13 @@ void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
sm->scanning = 0;
spin_unlock_irqrestore(&sm->lock, flags);
if (sm->associnfo.bssvalid) {
struct ieee80211softmac_network *net;
net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
if (net)
sm->set_channel(sm->dev, net->channel);
}
ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
}
EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
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