📄 airo.c
字号:
/* Question : is ASSOCIATED the only status * that is valid ? We want to catch handover * 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; } airo_send_event(dev); } else { memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; /* Send event to user space */ wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); }#endif /* WIRELESS_EXT > 13 */ } /* Check to see if there is something to receive */ if ( status & EV_RX ) { struct sk_buff *skb = NULL; u16 fc, len, hdrlen = 0;#pragma pack(1) struct { u16 status, len; u8 rssi[2]; u8 rate; u8 freq; u16 tmp[4]; } hdr;#pragma pack() u16 gap; u16 tmpbuf[4]; u16 *buffer; fid = IN4500( apriv, RXFID ); /* Get the packet length */ if (apriv->flags & FLAG_802_11) { bap_setup (apriv, fid, 4, BAP0); bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0); /* Bad CRC. Ignore packet */ if (le16_to_cpu(hdr.status) & 2) hdr.len = 0; if (apriv->wifidev == NULL) hdr.len = 0; } else { bap_setup (apriv, fid, 0x36, BAP0); bap_read (apriv, (u16*)&hdr.len, 2, BAP0); } len = le16_to_cpu(hdr.len); if (len > 2312) { printk( KERN_ERR "airo: Bad size %d\n", len ); len = 0; } if (len) { if (apriv->flags & FLAG_802_11) { bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); fc = le16_to_cpu(fc); switch (fc & 0xc) { case 4: if ((fc & 0xe0) == 0xc0) hdrlen = 10; else hdrlen = 16; break; case 8: if ((fc&0x300)==0x300){ hdrlen = 30; break; } default: hdrlen = 24; } } else hdrlen = ETH_ALEN * 2; skb = dev_alloc_skb( len + hdrlen + 2 ); if ( !skb ) { apriv->stats.rx_dropped++; len = 0; } } if (len) { buffer = (u16*)skb_put (skb, len + hdrlen); if (apriv->flags & FLAG_802_11) { buffer[0] = fc; bap_read (apriv, buffer + 1, hdrlen - 2, BAP0); if (hdrlen == 24) bap_read (apriv, tmpbuf, 6, BAP0); bap_read (apriv, &gap, sizeof(gap), BAP0); gap = le16_to_cpu(gap); if (gap) { if (gap <= 8) bap_read (apriv, tmpbuf, gap, BAP0); else printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n"); } bap_read (apriv, buffer + hdrlen/2, len, BAP0); } else { 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) {#ifdef WIRELESS_SPY if (apriv->spy_number > 0) { int i; char *sa; sa = (char*)buffer + ((apriv->flags & FLAG_802_11) ? 10 : 6); for (i=0; i<apriv->spy_number; i++) if (!memcmp(sa,apriv->spy_address[i],ETH_ALEN)) { if (!(apriv->flags & FLAG_802_11)) { bap_setup (apriv, fid, 8, BAP0); bap_read (apriv, (u16*)hdr.rssi, 2, BAP0); } apriv->spy_stat[i].qual = hdr.rssi[0]; if (apriv->rssi) apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; else apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2; apriv->spy_stat[i].noise = 0; apriv->spy_stat[i].updated = 3; break; } }#endif /* WIRELESS_SPY */ OUT4500( apriv, EVACK, EV_RX); if (apriv->flags & FLAG_802_11) { skb->mac.raw = skb->data; skb->pkt_type = PACKET_OTHERHOST; skb->dev = apriv->wifidev; skb->protocol = htons(ETH_P_802_2); } else { skb->dev = dev; skb->protocol = eth_type_trans(skb,dev); } skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); } else OUT4500( apriv, EVACK, EV_RX); } /* Check to see if a packet has been transmitted */ if ( status & ( EV_TX|EV_TXEXC ) ) { int i; int len = 0; int index = -1; fid = IN4500(apriv, TXCOMPLFID); for( i = 0; i < MAX_FIDS; i++ ) { if ( ( apriv->fids[i] & 0xffff ) == fid ) { len = apriv->fids[i] >> 16; index = i; /* Set up to be used again */ apriv->fids[i] &= 0xffff; } } if (index != -1) { netif_wake_queue(dev); if (status & EV_TXEXC) get_tx_error(apriv, index); } OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); if (index==-1) { printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); } } if ( status & ~STATUS_INTS & ~IGNORE_INTS ) printk( KERN_WARNING "airo: Got weird status %x\n", status & ~STATUS_INTS & ~IGNORE_INTS ); } if (savedInterrupts) OUT4500( apriv, EVINTEN, savedInterrupts ); /* done.. */ return;}/* * Routines to talk to the card *//* * This was originally written for the 4500, hence the name * NOTE: If use with 8bit mode and SMP bad things will happen! * Why would some one do 8 bit IO in an SMP machine?!? */static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) { if ( !do8bitIO ) outw( val, ai->dev->base_addr + reg ); else { outb( val & 0xff, ai->dev->base_addr + reg ); outb( val >> 8, ai->dev->base_addr + reg + 1 ); }}static u16 IN4500( struct airo_info *ai, u16 reg ) { unsigned short rc; if ( !do8bitIO ) rc = inw( ai->dev->base_addr + reg ); else { rc = inb( ai->dev->base_addr + reg ); rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8; } return rc;}static int enable_MAC( struct airo_info *ai, Resp *rsp ) { int rc; Cmd cmd; /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" * Note : we could try to use !netif_running(dev) in enable_MAC() * instead of this flag, but I don't trust it *within* the * open/close functions, and testing both flags together is * "cheaper" - Jean II */ if (ai->flags & (FLAG_RADIO_OFF|FLAG_RADIO_DOWN)) return SUCCESS; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_ENABLE; if (test_bit(FLAG_LOCKED, &ai->flags) != 0) return issuecommand(ai, &cmd, rsp); if (down_interruptible(&ai->sem)) return -ERESTARTSYS; rc = issuecommand(ai, &cmd, rsp); up(&ai->sem); return rc;}static void disable_MAC( struct airo_info *ai ) { Cmd cmd; Resp rsp; memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_DISABLE; // disable in case already enabled if (test_bit(FLAG_LOCKED, &ai->flags) != 0) { issuecommand(ai, &cmd, &rsp); return; } if (down_interruptible(&ai->sem)) return; issuecommand(ai, &cmd, &rsp); up(&ai->sem);}static void enable_interrupts( struct airo_info *ai ) { /* Reset the status register */ u16 status = IN4500( ai, EVSTAT ); OUT4500( ai, EVACK, status ); /* Enable the interrupts */ OUT4500( ai, EVINTEN, STATUS_INTS ); /* Note there is a race condition between the last two lines that I dont know how to get rid of right now... */}static void disable_interrupts( struct airo_info *ai ) { OUT4500( ai, EVINTEN, 0 );}static u16 setup_card(struct airo_info *ai, u8 *mac){ Cmd cmd; Resp rsp; int status; int i; SsidRid mySsid; u16 lastindex; WepKeyRid wkr; int rc; memset( &mySsid, 0, sizeof( mySsid ) ); if (ai->flash) { kfree (ai->flash); ai->flash = NULL; } /* The NOP is the first step in getting the card going */ cmd.cmd = NOP; cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; if (down_interruptible(&ai->sem)) return ERROR; if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) { up(&ai->sem); return ERROR; } memset(&cmd, 0, sizeof(cmd)); cmd.cmd = MAC_DISABLE; // disable in case already enabled if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) { up(&ai->sem); return ERROR; } // Let's figure out if we need to use the AUX port cmd.cmd = CMD_ENABLEAUX; if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { up(&ai->sem); printk(KERN_ERR "airo: Error checking for AUX port\n"); return ERROR; } if (!aux_bap || rsp.status & 0xff00) { ai->bap_read = fast_bap_read; printk(KERN_DEBUG "airo: Doing fast bap_reads\n"); } else { ai->bap_read = aux_bap_read; printk(KERN_DEBUG "airo: Doing AUX bap_reads\n"); } 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 { if (ai->rssi) { kfree(ai->rssi); ai->rssi = NULL; } 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]; } /* Check to see if there are any insmod configured rates to add */ if ( rates ) { int i = 0; if ( rates[0] ) memset(ai->config.rates,0,sizeof(ai->config.rates)); for( i = 0; i < 8 && rates[i]; i++ ) { ai->config.rates[i] = rates[i]; } } if ( basic_rate > 0 ) { int i; for( i = 0; i < 8; i++ ) { if ( ai->config.rates[i] == basic_rate || !ai->config.rates ) { ai->config.rates[i] = basic_rate | 0x80; break; } } } ai->need_commit = 1; } /* Setup the SSIDs if present */ if ( ssids[0] ) { int i; for( i = 0; i < 3 && ssids[i]; i++ ) { mySsid.ssids[i].len = strlen(ssids[i]); if ( mySsid.ssids[i].len > 32 ) mySsid.ssids[i].len = 32; memcpy(mySsid.ssids[i].ssid, ssids[i], mySsid.ssids[i].len); } } status = writeConfigRid(ai); if ( status != SUCCESS ) return ERROR; /* Set up the SSID list */ status = writeSsidRid(ai, &mySsid); if ( status != SUCCESS ) return ERROR; status = enable_MAC(ai, &rsp); 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 ); return ERROR; } /* Grab the initial wep key, we gotta save it for auto_wep */ rc = readWepKeyRid(ai, &wkr, 1); if (rc == SUCCESS) do { lastindex = wkr.kindex; if (wkr.kindex == 0xffff) { ai->defindex = wkr.mac[0]; } rc = readWepKeyRid(ai, &wkr, 0); } while(lastindex != wkr.kindex); if (auto_wep && !timer_pending(&ai->timer)) { ai->timer.expires = RUN_AT(HZ*3); add_timer(&ai->timer); } return SUCCESS;}static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { // Im really paranoid about letting it run forever! int max_tries = 600000; if (sendcommand(ai, pCmd) == (u16)ERROR) return ERROR; while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { if (!in_interrupt() && (max_tries & 255) == 0) schedule(); } if ( max_tries == -1 ) { printk( KERN_ERR "airo: Max tries exceeded waiting for command\n" ); return ERROR; } completecommand(ai, pRsp); return SUCCESS;}static u16 sendcommand(struct airo_info *ai, Cmd *pCmd) { // Im
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -