Commit ca2c4b26 authored by Javier Achirica's avatar Javier Achirica Committed by Jeff Garzik

airo wireless net drvr: add Cisco MIC support

Conditionally enabled when out-of-tree, but open source, crypto lib
is present.
parent de396e84
......@@ -80,6 +80,14 @@ static struct pci_driver airo_driver = {
#include <linux/delay.h>
#endif
/* Support Cisco MIC feature */
/* As this feature requires the AES encryption algorithm, it is not included
in the kernel tree. If you want to enable it, you need to download the
aes.h, aestab.h and mic.h files from the CVS at
http://sf.net/projects/airo-linux/ Put the files in the same directory
as airo.c and compile normally */
#undef MICSUPPORT
/* Hack to do some power saving */
#define POWER_ON_DOWN
......@@ -276,42 +284,41 @@ static int do8bitIO = 0;
#define NO_PACKET -2
/* Commands */
#define NOP2 0x00
#define MAC_ENABLE 0x01
#define MAC_ENABLETX 0x101
#define CMD_ENABLEAUX 0x111
#define MAC_ENABLERX 0x201
#define MAC_DISABLE 0x02
#define CMD_LOSE_SYNC 0x03
#define CMD_LOSE_SYNC_BSS 0x103
#define CMD_SOFTRESET 0x04
#define HOSTSLEEP 0x05
#define CMD_MAGICPACKET 0x06
#define CMD_SETWAKEMASK 0x07
#define CMD_SAVECONFIG 0x108
#define CMD_READCONFIG 0x08
#define CMD_SETMODE 0x09
#define CMD_ALLOCATETX 0x0A
#define CMD_TRANSMIT 0x0B
#define CMD_DEALLOC 0x0C
#define CMD_LISTBSS 0x103
#define NOP 0x10
#define CMD_WORKAROUND 0x11
#define CMD_ACCESS 0x21
#define CMD_WRITERID 0x121
#define CMD_PCIBAP 0x22
#define CMD_PCIAUX 0x23
#define CMD_ALLOCTLV 0x28
#define CMD_GETTLV 0x29
#define CMD_PUTTLV 0x2A
#define CMD_DELTLV 0x2B
#define CMD_FINDNEXTTLV 0x2C
#define CMD_SETPHYREG 0x3E
#define CMD_TXTEST 0x3F
#define CMD_NOPSPNODES 0x30
#define CMD_USEPSPNODES 0x130
#define CMD_SETCW 0x31
#define CMD_SETPCF 0x32
#define NOP2 0x0000
#define MAC_ENABLE 0x0001
#define MAC_DISABLE 0x0002
#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
#define CMD_SOFTRESET 0x0004
#define HOSTSLEEP 0x0005
#define CMD_MAGIC_PKT 0x0006
#define CMD_SETWAKEMASK 0x0007
#define CMD_READCFG 0x0008
#define CMD_SETMODE 0x0009
#define CMD_ALLOCATETX 0x000a
#define CMD_TRANSMIT 0x000b
#define CMD_DEALLOCATETX 0x000c
#define NOP 0x0010
#define CMD_WORKAROUND 0x0011
#define CMD_ACCESS 0x0021
#define CMD_PCIBAP 0x0022
#define CMD_PCIAUX 0x0023
#define CMD_ALLOCBUF 0x0028
#define CMD_GETTLV 0x0029
#define CMD_PUTTLV 0x002a
#define CMD_DELTLV 0x002b
#define CMD_FINDNEXTTLV 0x002c
#define CMD_PSPNODES 0x0030
#define CMD_SETCW 0x0031
#define CMD_SETPCF 0x0032
#define CMD_SETPHYREG 0x003e
#define CMD_TXTEST 0x003f
#define MAC_ENABLETX 0x0101
#define CMD_LISTBSS 0x0103
#define CMD_SAVECFG 0x0108
#define CMD_ENABLEAUX 0x0111
#define CMD_WRITERID 0x0121
#define CMD_USEPSPNODES 0x0130
#define MAC_ENABLERX 0x0201
/* Command errors */
#define ERROR_QUALIF 0x00
......@@ -398,10 +405,10 @@ static int do8bitIO = 0;
#define EV_AWAKE 0x100
#define EV_UNKNOWN 0x800
#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX)
#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX | EV_MIC )
#ifdef CHECK_UNKNOWN_INTS
#define IGNORE_INTS ( EV_MIC | EV_CMD | EV_UNKNOWN)
#define IGNORE_INTS ( EV_CMD | EV_UNKNOWN)
#else
#define IGNORE_INTS (~STATUS_INTS)
#endif
......@@ -433,6 +440,7 @@ static int do8bitIO = 0;
#define RID_UNKNOWN54 0xFF54
#define RID_UNKNOWN55 0xFF55
#define RID_UNKNOWN56 0xFF56
#define RID_MIC 0xFF57
#define RID_STATS16 0xFF60
#define RID_STATS16DELTA 0xFF61
#define RID_STATS16DELTACLEAR 0xFF62
......@@ -511,6 +519,7 @@ typedef struct {
#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */
#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */
#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */
#define MODE_MIC (1<<15) /* enable MIC */
u16 rmode; /* receive mode */
#define RXMODE_BC_MC_ADDR 0
#define RXMODE_BC_ADDR 1 /* ignore multicasts */
......@@ -682,6 +691,7 @@ typedef struct {
u16 softCap;
u16 bootBlockVer;
u16 requiredHard;
u16 extSoftCap;
} CapabilityRid;
typedef struct {
......@@ -724,6 +734,37 @@ typedef struct {
tdsRssiEntry x[256];
} tdsRssiRid;
typedef struct {
u16 len;
u16 state;
u16 multicastValid;
u8 multicast[16];
u16 unicastValid;
u8 unicast[16];
} MICRid;
typedef struct {
u16 typelen;
union {
u8 snap[8];
struct {
u8 dsap;
u8 ssap;
u8 control;
u8 orgcode[3];
u8 fieldtype[2];
} llc;
} u;
u32 mic;
u32 seq;
} MICBuffer;
typedef struct {
u8 da[ETH_ALEN];
u8 sa[ETH_ALEN];
} etherHead;
#pragma pack()
#define TXCTL_TXOK (1<<1) /* report if tx is ok */
......@@ -768,10 +809,13 @@ typedef struct {
#define AIROGSTAT 8
#define AIROGSTATSC32 9
#define AIROGSTATSD32 10
#define AIROGMICRID 11
#define AIROGMICSTATS 12
#define AIROGFLAGS 13
/* Leave gap of 40 commands after AIROGSTATSD32 for future */
#define AIROPCAP AIROGSTATSD32 + 40
#define AIROPCAP AIROGSTATSD32 + 40
#define AIROPVLIST AIROPCAP + 1
#define AIROPSLIST AIROPVLIST + 1
#define AIROPCFG AIROPSLIST + 1
......@@ -803,6 +847,45 @@ typedef struct aironet_ioctl {
} aironet_ioctl;
#endif /* CISCO_EXT */
#define NUM_MODULES 2
#define MIC_MSGLEN_MAX 2400
#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
typedef struct {
u32 size; // size
u8 enabled; // MIC enabled or not
u32 rxSuccess; // successful packets received
u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison
u32 rxNotMICed; // pkts dropped due to not being MIC'd
u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed
u32 rxWrongSequence; // pkts dropped due to sequence number violation
u32 reserve[32];
} mic_statistics;
typedef struct {
u32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
u64 accum; // accumulated mic, reduced to u32 in final()
int position; // current position (byte offset) in message
union {
u8 d8[4];
u32 d32;
} part; // saves partial message word across update() calls
} emmh32_context;
typedef struct {
emmh32_context seed; // Context - the seed
u32 rx; // Received sequence number
u32 tx; // Tx sequence number
u32 window; // Start of window
u8 valid; // Flag to say if context is valid or not
u8 key[16];
} miccntx;
typedef struct {
miccntx mCtx; // Multicast context
miccntx uCtx; // Unicast context
} mic_module;
#ifdef WIRELESS_EXT
// Frequency list (map channels to frequencies)
const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
......@@ -832,7 +915,7 @@ struct iw_request_info {};
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */
static const char version[] = "airo.c 0.5 (Ben Reed & Javier Achirica)";
static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
struct airo_info;
......@@ -875,6 +958,12 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp);
static int writerids(struct net_device *dev, aironet_ioctl *comp);
int flashcard(struct net_device *dev, aironet_ioctl *comp);
#endif /* CISCO_EXT */
#ifdef MICSUPPORT
static void micinit(struct airo_info *ai, MICRid *micr);
static void micsetup(struct airo_info *ai);
static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
#endif
struct airo_info {
struct net_device_stats stats;
......@@ -899,6 +988,10 @@ struct airo_info {
#define FLAG_RADIO_DOWN 0x08 /* ifup/ifdown disabling of MAC */
#define FLAG_LOCKED 2 /* 0x04 - use as a bit offset */
#define FLAG_FLASHING 0x10
#define FLAG_ADHOC 0x01 /* Needed by MIC */
#define FLAG_MIC_CAPABLE 0x20
#define FLAG_UPDATE_MULTI 0x40
#define FLAG_UPDATE_UNI 0x80
#define FLAG_802_11 0x200
int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
......@@ -923,6 +1016,10 @@ struct airo_info {
struct iw_quality spy_stat[IW_MAX_SPY];
#endif /* WIRELESS_SPY */
#endif /* WIRELESS_EXT */
/* MIC stuff */
mic_module mod[2];
mic_statistics micstats;
struct tq_struct mic_task;
};
static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
......@@ -935,6 +1032,10 @@ static int setup_proc_entry( struct net_device *dev,
static int takedown_proc_entry( struct net_device *dev,
struct airo_info *apriv );
#ifdef MICSUPPORT
#include "mic.h"
#endif
static int readBSSListRid(struct airo_info *ai, int first,
BSSListRid *list) {
int rc;
......@@ -1065,6 +1166,11 @@ static int writeConfigRid(struct airo_info*ai) {
ai->need_commit = 0;
checkThrottle(ai);
if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS)
ai->flags |= FLAG_ADHOC;
else
ai->flags &= ~FLAG_ADHOC;
cfgr = ai->config;
for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
......@@ -1713,6 +1819,24 @@ static void airo_send_event(struct net_device *dev) {
}
#endif
static void airo_read_mic(struct airo_info *ai) {
MICRid mic_rid;
if (down_trylock(&ai->sem) == 0) {
__set_bit(FLAG_LOCKED, &ai->flags);
PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid));
clear_bit(FLAG_LOCKED, &ai->flags);
up(&ai->sem);
#ifdef MICSUPPORT
micinit (ai, &mic_rid);
#endif
} else {
ai->mic_task.routine = (void (*)(void *))airo_read_mic;
ai->mic_task.data = (void *)ai;
schedule_task(&ai->mic_task);
}
}
static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
struct net_device *dev = (struct net_device *)dev_id;
u16 status;
......@@ -1737,6 +1861,10 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
OUT4500( apriv, EVINTEN, 0 );
}
if ( status & EV_MIC ) {
OUT4500( apriv, EVACK, EV_MIC );
airo_read_mic( apriv );
}
if ( status & EV_LINK ) {
#if WIRELESS_EXT > 13
union iwreq_data wrqu;
......@@ -1785,6 +1913,7 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
struct task_struct *task = apriv->task;
if (task)
wake_up_process (task);
apriv->flags|=FLAG_UPDATE_UNI|FLAG_UPDATE_MULTI;
}
#if WIRELESS_EXT > 13
/* Question : is ASSOCIATED the only status
......@@ -1902,7 +2031,26 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
bap_read (apriv, buffer + hdrlen/2, len, BAP0);
} else {
bap_read (apriv, buffer,len + hdrlen,BAP0);
MICBuffer micbuf;
bap_read (apriv, buffer, ETH_ALEN*2, BAP0);
if (apriv->micstats.enabled) {
bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0);
if (ntohs(micbuf.typelen) > 0x05DC)
bap_setup (apriv, fid, 0x44, BAP0);
else {
len -= sizeof(micbuf);
if (len < 48)
len = 48;
skb_trim (skb, len + hdrlen);
}
}
bap_read(apriv,buffer+ETH_ALEN,len,BAP0);
#ifdef MICSUPPORT
if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) {
dev_kfree_skb_irq (skb);
len = 0;
}
#endif
}
}
if (len) {
......@@ -2122,30 +2270,40 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
up(&ai->sem);
if (ai->config.len == 0) {
tdsRssiRid rssi_rid;
CapabilityRid cap_rid;
// general configuration (read/modify/write)
status = readConfigRid(ai);
if ( status != SUCCESS ) return ERROR;
status = readCapabilityRid(ai, &cap_rid);
if ( status != SUCCESS ) return ERROR;
status = PC4500_readrid(ai,RID_RSSI,&rssi_rid,sizeof(rssi_rid));
if ( status == SUCCESS ) {
if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512);
}
else {
CapabilityRid cap_rid;
if (ai->rssi) {
kfree(ai->rssi);
ai->rssi = NULL;
}
status = readCapabilityRid(ai, &cap_rid);
if ((status == SUCCESS) && (cap_rid.softCap & 8))
if (cap_rid.softCap & 8)
ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
else
printk(KERN_WARNING "airo: unknown received signal level scale\n");
}
ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
#ifdef MICSUPPORT
if ((cap_rid.len==sizeof(cap_rid)) && (cap_rid.extSoftCap&1)) {
ai->config.opmode |= MODE_MIC;
ai->flags |= FLAG_MIC_CAPABLE;
micsetup(ai);
}
#endif
/* Save off the MAC */
for( i = 0; i < ETH_ALEN; i++ ) {
mac[i] = ai->config.macAddr[i];
......@@ -2170,8 +2328,6 @@ static u16 setup_card(struct airo_info *ai, u8 *mac)
}
}
}
if (auto_wep)
ai->config.authType = AUTH_SHAREDKEY;
ai->need_commit = 1;
}
......@@ -2539,22 +2695,38 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket)
u16 payloadLen;
Cmd cmd;
Resp rsp;
int miclen = 0;
u16 txFid = len;
MICBuffer pMic;
len >>= 16;
if (len < ETH_ALEN * 2) {
printk( KERN_WARNING "Short packet %d\n", len );
return ERROR;
}
len -= ETH_ALEN * 2;
#ifdef MICSUPPORT
if ((ai->flags & FLAG_MIC_CAPABLE) && ai->micstats.enabled &&
(ntohs(((u16 *)pPacket)[6]) != 0x888E)) {
if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS)
return ERROR;
miclen = sizeof(pMic);
}
#endif
// packet is destination[6], source[6], payload[len-12]
// write the payload length and dst/src/payload
if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
/* The hardware addresses aren't counted as part of the payload, so
* we have to subtract the 12 bytes for the addresses off */
payloadLen = cpu_to_le16(len-12);
payloadLen = cpu_to_le16(len + miclen);
bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
bap_write(ai, (const u16*)pPacket, len, BAP1);
bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1);
if (miclen)
bap_write(ai, (const u16*)&pMic, miclen, BAP1);
bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1);
// issue the transmit command
memset( &cmd, 0, sizeof( cmd ) );
cmd.cmd = CMD_TRANSMIT;
......@@ -3037,10 +3209,11 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
need_reset = 1;
ai->config.rmode &= 0xfe00;
ai->flags &= ~FLAG_802_11;
ai->config.opmode &= 0xFF00;
if ( line[0] == 'a' ) {
ai->config.opmode = 0;
ai->config.opmode |= 0;
} else {
ai->config.opmode = 1;
ai->config.opmode |= 1;
if ( line[0] == 'r' ) {
ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
ai->flags |= FLAG_802_11;
......@@ -3274,10 +3447,10 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
"DataRates: %d %d %d %d %d %d %d %d\n"
"Channel: %d\n"
"XmitPower: %d\n",
ai->config.opmode == 0 ? "adhoc" :
ai->config.opmode == 1 ? get_rmode(ai->config.rmode):
ai->config.opmode == 2 ? "AP" :
ai->config.opmode == 3 ? "AP RPTR" : "Error",
(ai->config.opmode & 0xFF) == 0 ? "adhoc" :
(ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode):
(ai->config.opmode & 0xFF) == 2 ? "AP" :
(ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error",
ai->flags&FLAG_RADIO_OFF ? "off" : "on",
ai->config.nodeName,
ai->config.powerSaveMode == 0 ? "CAM" :
......@@ -4335,16 +4508,20 @@ static int airo_set_mode(struct net_device *dev,
switch(*uwrq) {
case IW_MODE_ADHOC:
local->config.opmode = MODE_STA_IBSS;
local->config.opmode &= 0xFF00;
local->config.opmode |= MODE_STA_IBSS;
break;
case IW_MODE_INFRA:
local->config.opmode = MODE_STA_ESS;
local->config.opmode &= 0xFF00;
local->config.opmode |= MODE_STA_ESS;
break;
case IW_MODE_MASTER:
local->config.opmode = MODE_AP;
local->config.opmode &= 0xFF00;
local->config.opmode |= MODE_AP;
break;
case IW_MODE_REPEAT:
local->config.opmode = MODE_AP_RPTR;
local->config.opmode &= 0xFF00;
local->config.opmode |= MODE_AP_RPTR;
break;
default:
return -EINVAL;
......@@ -5637,7 +5814,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/* Seperate R/W functions bracket legality here
*/
if ( com.command <= AIROGSTATSD32 )
if ( com.command <= AIROGMICSTATS )
rc = readrids(dev,&com);
else if ( com.command >= AIROPCAP && com.command <= AIROPLEAPUSR )
rc = writerids(dev,&com);
......@@ -5730,8 +5907,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
switch(comp->command)
{
case AIROGCAP: ridcode = RID_CAPABILITIES; break;
case AIROGCFG: ridcode = RID_CONFIG; break;
case AIROPCFG: writeConfigRid ((struct airo_info *)dev->priv);
case AIROGCFG: writeConfigRid (ai);
ridcode = RID_CONFIG; break;
case AIROGSLIST: ridcode = RID_SSID; break;
case AIROGVLIST: ridcode = RID_APLIST; break;
......@@ -5750,12 +5926,17 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
case AIROGSTAT: ridcode = RID_STATUS; break;
case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
case AIROGSTATSC32: ridcode = RID_STATS; break;
case AIROGMICSTATS:
if (copy_to_user(comp->data, &ai->micstats,
min((int)comp->len,(int)sizeof(ai->micstats))))
return -EFAULT;
return 0;
default:
return -EINVAL;
break;
}
PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
PC4500_readrid(ai,ridcode,iobuf,sizeof(iobuf));
/* get the count of bytes in the rid docs say 1st 2 bytes is it.
* then return it to the user
* 9/22/2000 Honor user given length
......@@ -5773,7 +5954,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
static int writerids(struct net_device *dev, aironet_ioctl *comp) {
struct airo_info *ai = dev->priv;
int ridcode;
int ridcode, enabled;
Resp rsp;
static int (* writer)(struct airo_info *, u16 rid, const void *, int);
unsigned char iobuf[2048];
......@@ -5793,7 +5974,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
case AIROPSIDS: ridcode = RID_SSID; break;
case AIROPCAP: ridcode = RID_CAPABILITIES; break;
case AIROPAPLIST: ridcode = RID_APLIST; break;
case AIROPCFG: ((struct airo_info *)dev->priv)->config.len = 0;
case AIROPCFG: ai->config.len = 0;
ridcode = RID_CONFIG; break;
case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
......@@ -5805,7 +5986,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* same with MAC off
*/
case AIROPMACON:
if (enable_MAC(dev->priv, &rsp) != 0)
if (enable_MAC(ai, &rsp) != 0)
return -EIO;
return 0;
......@@ -5814,7 +5995,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* as disable_MAC. it's probably so short the compiler does not gen one.
*/
case AIROPMACOFF:
disable_MAC(dev->priv);
disable_MAC(ai);
return 0;
/* This command merely clears the counts does not actually store any data
......@@ -5822,9 +6003,11 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* writerid routines.
*/
case AIROPSTCLR:
ridcode = RID_STATSDELTACLEAR;
PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,sizeof(iobuf));
PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
enabled = ai->micstats.enabled;
memset(&ai->micstats,0,sizeof(ai->micstats));
ai->micstats.enabled = enabled;
if (copy_to_user(comp->data, iobuf,
min((int)comp->len, (int)sizeof(iobuf))))
......@@ -5839,7 +6022,20 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
if (copy_from_user(iobuf,comp->data,comp->len))
return -EFAULT;
if((*writer)((struct airo_info *)dev->priv, ridcode, iobuf,comp->len))
if (comp->command == AIROPCFG) {
ConfigRid *cfg = (ConfigRid *)iobuf;
if (ai->flags & FLAG_MIC_CAPABLE)
cfg->opmode |= MODE_MIC;
if ((cfg->opmode & 0xFF) == MODE_STA_IBSS)
ai->flags |= FLAG_ADHOC;
else
ai->flags &= ~FLAG_ADHOC;
}
if((*writer)(ai, ridcode, iobuf,comp->len))
return -EIO;
return 0;
}
......
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