📄 atmel.c
字号:
return 1; } frame_ctl = IEEE802_11_FTYPE_DATA; header.duration_id = 0; header.seq_ctl = 0; if (priv->wep_is_on) frame_ctl |= IEEE802_11_FCTL_WEP; if (priv->operating_mode == IW_MODE_ADHOC) { memcpy(&header.addr1, skb->data, 6); memcpy(&header.addr2, dev->dev_addr, 6); memcpy(&header.addr3, priv->BSSID, 6); } else { frame_ctl |= IEEE802_11_FCTL_TODS; memcpy(&header.addr1, priv->CurrentBSSID, 6); memcpy(&header.addr2, dev->dev_addr, 6); memcpy(&header.addr3, skb->data, 6); } if (priv->use_wpa) memcpy(&header.addr4, SNAP_RFC1024, 6); header.frame_ctl = cpu_to_le16(frame_ctl); /* Copy the wireless header into the card */ atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); /* Copy the packet sans its 802.3 header addresses which have been replaced */ atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; /* low bit of first byte of destination tells us if broadcast */ tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); dev->trans_start = jiffies; priv->stats.tx_bytes += len; spin_unlock_irqrestore(&priv->irqlock, flags); spin_unlock_bh(&priv->timerlock); dev_kfree_skb(skb); return 0; }static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, u8 *body, int body_len){ u16 buff; int len = MGMT_FRAME_BODY_OFFSET + body_len; if (!(buff = find_tx_buff(priv, len))) return; atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); priv->tx_buff_tail += len; tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT);} static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc){ /* fast path: unfragmented packet copy directly into skbuf */ u8 mac4[6]; struct sk_buff *skb; unsigned char *skbp; /* get the final, mac 4 header field, this tells us encapsulation */ atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); msdu_size -= 6; if (priv->do_rx_crc) { crc = crc32_le(crc, mac4, 6); msdu_size -= 4; } if (!(skb = dev_alloc_skb(msdu_size + 14))) { priv->stats.rx_dropped++; return; } skb_reserve(skb, 2); skbp = skb_put(skb, msdu_size + 12); atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); if (priv->do_rx_crc) { u32 netcrc; crc = crc32_le(crc, skbp + 12, msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { priv->stats.rx_crc_errors++; dev_kfree_skb(skb); return; } } memcpy(skbp, header->addr1, 6); /* destination address */ if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) memcpy(&skbp[6], header->addr3, 6); else memcpy(&skbp[6], header->addr2, 6); /* source address */ priv->dev->last_rx=jiffies; skb->dev = priv->dev; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); priv->stats.rx_bytes += 12 + msdu_size; priv->stats.rx_packets++;}/* Test to see if the packet in card memory at packet_loc has a valid CRC It doesn't matter that this is slow: it is only used to proble the first few packets. */static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size){ int i = msdu_size - 4; u32 netcrc, crc = 0xffffffff; if (msdu_size < 4) return 0; atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); atmel_writeAR(priv->dev, packet_loc); while (i--) { u8 octet = atmel_read8(priv->dev, DR); crc = crc32_le(crc, &octet, 1); } return (crc ^ 0xffffffff) == netcrc;}static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags){ u8 mac4[6]; u8 source[6]; struct sk_buff *skb; if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) memcpy(source, header->addr3, 6); else memcpy(source, header->addr2, 6); rx_packet_loc += 24; /* skip header */ if (priv->do_rx_crc) msdu_size -= 4; if (frag_no == 0) { /* first fragment */ atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); msdu_size -= 6; rx_packet_loc += 6; if (priv->do_rx_crc) crc = crc32_le(crc, mac4, 6); priv->frag_seq = seq_no; priv->frag_no = 1; priv->frag_len = msdu_size; memcpy(priv->frag_source, source, 6); memcpy(&priv->rx_buf[6], source, 6); memcpy(priv->rx_buf, header->addr1, 6); atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); if (priv->do_rx_crc) { u32 netcrc; crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { priv->stats.rx_crc_errors++; memset(priv->frag_source, 0xff, 6); } } } else if (priv->frag_no == frag_no && priv->frag_seq == seq_no && memcmp(priv->frag_source, source, 6) == 0) { atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], rx_packet_loc, msdu_size); if (priv->do_rx_crc) { u32 netcrc; crc = crc32_le(crc, &priv->rx_buf[12 + priv->frag_len], msdu_size); atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); if ((crc ^ 0xffffffff) != netcrc) { priv->stats.rx_crc_errors++; memset(priv->frag_source, 0xff, 6); more_frags = 1; /* don't send broken assembly */ } } priv->frag_len += msdu_size; priv->frag_no++; if (!more_frags) { /* last one */ memset(priv->frag_source, 0xff, 6); if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { priv->stats.rx_dropped++; } else { skb_reserve(skb, 2); memcpy(skb_put(skb, priv->frag_len + 12), priv->rx_buf, priv->frag_len + 12); priv->dev->last_rx = jiffies; skb->dev = priv->dev; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); priv->stats.rx_bytes += priv->frag_len + 12; priv->stats.rx_packets++; } } } else priv->wstats.discard.fragment++;} static void rx_done_irq(struct atmel_private *priv){ int i; struct ieee802_11_hdr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && i < priv->host_info.rx_desc_count; i++) { u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); u32 crc = 0xffffffff; if (status != RX_STATUS_SUCCESS) { if (status == 0xc1) /* determined by experiment */ priv->wstats.discard.nwid++; else priv->stats.rx_errors++; goto next; } msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); if (msdu_size < 30) { priv->stats.rx_errors++; goto next; } /* Get header as far as end of seq_ctl */ atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); frame_ctl = le16_to_cpu(header.frame_ctl); seq_control = le16_to_cpu(header.seq_ctl); /* probe for CRC use here if needed once five packets have arrived with the same crc status, we assume we know what's happening and stop probing */ if (priv->probe_crc) { if (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) { priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); } else { priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); } if (priv->do_rx_crc) { if (priv->crc_ok_cnt++ > 5) priv->probe_crc = 0; } else { if (priv->crc_ko_cnt++ > 5) priv->probe_crc = 0; } } /* don't CRC header when WEP in use */ if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) { crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); } msdu_size -= 24; /* header */ if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS; u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG; u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4; if (!more_fragments && packet_fragment_no == 0 ) { fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); } else { frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, packet_sequence_no, packet_fragment_no, more_fragments); } } if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) { /* copy rest of packet into buffer */ atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); /* we use the same buffer for frag reassembly and control packets */ memset(priv->frag_source, 0xff, 6); if (priv->do_rx_crc) { /* last 4 octets is crc */ msdu_size -= 4; crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { priv->stats.rx_crc_errors++; goto next; } } atmel_management_frame(priv, &header, msdu_size, atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); } next: /* release descriptor */ atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) priv->rx_desc_head++; else priv->rx_desc_head = 0; }} static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct atmel_private *priv = netdev_priv(dev); u8 isr; int i = -1; static u8 irq_order[] = { ISR_OUT_OF_RANGE, ISR_RxCOMPLETE, ISR_TxCOMPLETE, ISR_RxFRAMELOST, ISR_FATAL_ERROR, ISR_COMMAND_COMPLETE, ISR_IBSS_MERGE, ISR_GENERIC_IRQ }; if (priv->card && priv->present_callback && !(*priv->present_callback)(priv->card)) return IRQ_HANDLED; /* In this state upper-level code assumes it can mess with the card unhampered by interrupts which may change register state. Note that even though the card shouldn't generate interrupts the inturrupt line may be shared. This allows card setup to go on without disabling interrupts for a long time. */ if (priv->station_state == STATION_STATE_DOWN) return IRQ_NONE; atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ while (1) { if (!atmel_lock_mac(priv)) { /* failed to contact card */ printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); return IRQ_HANDLED; } isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); if (!isr) { atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ return i == -1 ? IRQ_NONE : IRQ_HANDLED; } atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ for (i = 0; i < sizeof(irq_order)/sizeof(u8); i++) if (isr & irq_order[i]) break; if (!atmel_lock_mac(priv)) { /* failed to contact card */ printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); return IRQ_HANDLED; } isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); isr ^= irq_order[i]; atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); switch (irq_order[i]) { case ISR_OUT_OF_RANGE: if (priv->operating_mode == IW_MODE_INFRA && priv->station_state == STATION_STATE_READY) { priv->station_is_associated = 0; atmel_scan(priv, 1); } break; case ISR_RxFRAMELOST: priv->wstats.discard.misc++; /* fall through */ case ISR_RxCOMPLETE: rx_done_irq(priv); break; case ISR_TxCOMPLETE: tx_done_irq(priv); break; case ISR_FATAL_ERROR: printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); break; case ISR_COMMAND_COMPLETE: atmel_command_irq(priv); break; case ISR_IBSS_MERGE: atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, priv->CurrentBSSID, 6); /* The WPA stuff cares about the current AP address */ if (priv->use_wpa)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -