static void fill_rt_header(void *buffer, struct zd_mac *mac, const struct ieee80211_rx_stats *stats, const struct rx_status *status) { struct zd_rt_hdr *hdr = buffer; hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; hdr->rt_hdr.it_pad = 0; hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr)); hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_RATE)); hdr->rt_flags = 0; if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP; hdr->rt_rate = stats->rate / 5; /* FIXME: 802.11a */ hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz( _zd_chip_get_channel(&mac->chip))); hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); }
static int fill_rx_stats(struct ieee80211_rx_stats *stats, const struct rx_status **pstatus, struct zd_mac *mac, const u8 *buffer, unsigned int length) { const struct rx_status *status; *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); if (status->frame_status & ZD_RX_ERROR) { /* FIXME: update? */ return -EINVAL; } memset(stats, 0, sizeof(struct ieee80211_rx_stats)); stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + + sizeof(struct rx_status)); /* FIXME: 802.11a */ stats->freq = IEEE80211_24GHZ_BAND; stats->received_channel = _zd_chip_get_channel(&mac->chip); stats->rssi = zd_rx_strength_percent(status->signal_strength); stats->signal = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL; stats->rate = zd_rx_rate(buffer, status); if (stats->rate) stats->mask |= IEEE80211_STATMASK_RATE; return 0; }
static int fill_rx_stats(struct ieee80211_rx_stats *stats, const struct rx_status **pstatus, struct zd_mac *mac, const u8 *buffer, unsigned int length) { const struct rx_status *status; *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status)); if (status->frame_status & ZD_RX_ERROR) { struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); ieee->stats.rx_errors++; if (status->frame_status & ZD_RX_TIMEOUT_ERROR) ieee->stats.rx_missed_errors++; else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) ieee->stats.rx_fifo_errors++; else if (status->frame_status & ZD_RX_DECRYPTION_ERROR) ieee->ieee_stats.rx_discards_undecryptable++; else if (status->frame_status & ZD_RX_CRC32_ERROR) { ieee->stats.rx_crc_errors++; ieee->ieee_stats.rx_fcs_errors++; } else if (status->frame_status & ZD_RX_CRC16_ERROR) ieee->stats.rx_crc_errors++; return -EINVAL; } memset(stats, 0, sizeof(struct ieee80211_rx_stats)); stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + + sizeof(struct rx_status)); /* FIXME: 802.11a */ stats->freq = IEEE80211_24GHZ_BAND; stats->received_channel = _zd_chip_get_channel(&mac->chip); stats->rssi = zd_rx_strength_percent(status->signal_strength); stats->signal = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL; stats->rate = zd_rx_rate(buffer, status); if (stats->rate) stats->mask |= IEEE80211_STATMASK_RATE; return 0; }
int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) { struct zd_mac *mac = zd_hw_mac(hw); struct ieee80211_rx_status stats; const struct rx_status *status; struct sk_buff *skb; int bad_frame = 0; u16 fc; bool is_qos, is_4addr, need_padding; if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ + FCS_LEN + sizeof(struct rx_status)) return -EINVAL; memset(&stats, 0, sizeof(stats)); /* Note about pass_failed_fcs and pass_ctrl access below: * mac locking intentionally omitted here, as this is the only unlocked * reader and the only writer is configure_filter. Plus, if there were * any races accessing these variables, it wouldn't really matter. * If mac80211 ever provides a way for us to access filter flags * from outside configure_filter, we could improve on this. Also, this * situation may change once we implement some kind of DMA-into-skb * RX path. */ /* Caller has to ensure that length >= sizeof(struct rx_status). */ status = (struct rx_status *) (buffer + (length - sizeof(struct rx_status))); if (status->frame_status & ZD_RX_ERROR) { if (mac->pass_failed_fcs && (status->frame_status & ZD_RX_CRC32_ERROR)) { stats.flag |= RX_FLAG_FAILED_FCS_CRC; bad_frame = 1; } else { return -EINVAL; } } stats.channel = _zd_chip_get_channel(&mac->chip); stats.freq = zd_channels[stats.channel - 1].freq; stats.phymode = MODE_IEEE80211G; stats.ssi = status->signal_strength; stats.signal = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); stats.rate = zd_rx_rate(buffer, status); length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status); buffer += ZD_PLCP_HEADER_SIZE; /* Except for bad frames, filter each frame to see if it is an ACK, in * which case our internal TX tracking is updated. Normally we then * bail here as there's no need to pass ACKs on up to the stack, but * there is also the case where the stack has requested us to pass * control frames on up (pass_ctrl) which we must consider. */ if (!bad_frame && filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) && !mac->pass_ctrl) return 0; fc = le16_to_cpu(*((__le16 *) buffer)); is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA); is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); need_padding = is_qos ^ is_4addr; skb = dev_alloc_skb(length + (need_padding ? 2 : 0)); if (skb == NULL) return -ENOMEM; if (need_padding) { /* Make sure the the payload data is 4 byte aligned. */ skb_reserve(skb, 2); } memcpy(skb_put(skb, length), buffer, length); ieee80211_rx_irqsafe(hw, skb, &stats); return 0; }