📄 atmel.c
字号:
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.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.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 void reset_irq_status(struct atmel_private *priv, u8 mask){ u8 isr; atmel_lock_mac(priv); isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); isr ^= mask; atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0);}static void service_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; struct atmel_private *priv = (struct atmel_private *) dev->priv; u8 isr; if (priv->card && priv->present_callback && !(*priv->present_callback)(priv->card)) return; atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ while (1) { if (!atmel_lock_mac(priv)) { printk(KERN_ALERT "%s: MAC gone away in ISR.\n", dev->name); /* bad things - don't re-enable interrupts */ return; } 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_ACKINT); /* acknowledge interrupt */ else break; /* no pending irqs */ if (isr & ISR_OUT_OF_RANGE) { reset_irq_status(priv, 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); } } else if (isr & ISR_RxCOMPLETE) { reset_irq_status(priv, ISR_RxCOMPLETE); rx_done_irq(priv); } else if (isr & ISR_TxCOMPLETE) { reset_irq_status(priv, ISR_TxCOMPLETE); tx_done_irq(priv); } else if (isr & ISR_RxFRAMELOST) { reset_irq_status(priv, ISR_RxFRAMELOST); priv->wstats.discard.misc++; rx_done_irq(priv); } else if (isr & ISR_FATAL_ERROR) { reset_irq_status(priv, ISR_FATAL_ERROR); printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); } else if (isr & ISR_COMMAND_COMPLETE) { reset_irq_status(priv, ISR_COMMAND_COMPLETE); atmel_command_irq(priv); } else if (isr & ISR_IBSS_MERGE) { reset_irq_status(priv, ISR_IBSS_MERGE); atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, priv->CurrentBSSID, 6); } else if (isr & ISR_GENERIC_IRQ) { reset_irq_status(priv, ISR_GENERIC_IRQ); printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name); } } atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ return;}static struct net_device_stats *atmel_get_stats (struct net_device *dev){ struct atmel_private *priv = (struct atmel_private *)dev->priv; return &priv->stats;}static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev){ struct atmel_private *priv = (struct atmel_private *)dev->priv; /* update the link quality here in case we are seeing no beacons at all to drive the process */ atmel_smooth_qual(priv); priv->wstats.status = priv->station_state; if (priv->operating_mode == IW_MODE_INFRA) { if (priv->station_state != STATION_STATE_READY) { priv->wstats.qual.qual = 0; priv->wstats.qual.level = 0; } priv->wstats.qual.noise = 0; priv->wstats.qual.updated = 7; } else { // Quality levels cannot be determined in ad-hoc mode, // because we can 'hear' more than one remote station. priv->wstats.qual.qual = 0; priv->wstats.qual.level = 0; priv->wstats.qual.noise = 0; priv->wstats.qual.updated = 0; priv->wstats.miss.beacon = 0; } return (&priv->wstats);}static int atmel_change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > 2312)) return -EINVAL; dev->mtu = new_mtu; return 0;}static int atmel_set_mac_address(struct net_device *dev, void *p){ struct sockaddr *addr = p; memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); reset_atmel_card(dev); return 0;}static int atmel_open (struct net_device *dev){ struct atmel_private *priv = (struct atmel_private *) dev->priv; priv->station_state = STATION_STATE_INITIALIZING; if (!reset_atmel_card(dev)) { priv->station_state = STATION_STATE_DOWN; return -EAGAIN; } return 0;}static int atmel_close (struct net_device *dev){ struct atmel_private *priv = (struct atmel_private *) dev->priv; if (netif_running(dev)) netif_stop_queue(dev); priv->station_state = STATION_STATE_DOWN; if (priv->bus_type == BUS_TYPE_PCCARD) atmel_write16(dev, GCR, 0x0060); atmel_write16(dev, GCR, 0x0040); return 0;}static int atmel_proc_output (char *buf, struct atmel_private *priv){ char *p = buf; char *s, *r, *c; p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); if (priv->station_state != STATION_STATE_DOWN) { p += sprintf(p, "Firmware version:\t%d.%d build %d ", priv->host_info.major_version, priv->host_info.minor_version, priv->host_info.build_version); if (priv->card_type != CARD_TYPE_EEPROM) p += sprintf(p, "[built-in]\n"); else if (priv->firmware) p += sprintf(p, "[%s loaded by host]\n", priv->firmware_id); else p += sprintf(p, "[%s loaded by hotplug]\n", priv->firmware_id); switch(priv->card_type) { case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break; case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break; case CARD_TYPE_EEPROM: c = "EEPROM"; break; default: c = "<unknown>"; } switch (priv->reg_domain) { case REG_DOMAIN_FCC: r = "USA"; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -