X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=net%2Fmac80211%2Frx.c;h=e65da5780cd38780ed6eccd2876b93077ccfbbfc;hb=98f0b0a3a412eade153c7cf00c6b863600980d89;hp=00f908d9275e3e69a92daf1cc4d6741015d051d5;hpb=2ba14a017a4ba8d2266316f481d4ad7400073d18;p=mv-sheeva.git diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 00f908d9275..e65da5780cd 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -61,8 +61,10 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, return 1; if (unlikely(skb->len < 16 + present_fcs_len + radiotap_len)) return 1; - if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == - cpu_to_le16(IEEE80211_FTYPE_CTL)) + if (((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FTYPE)) == + cpu_to_le16(IEEE80211_FTYPE_CTL)) && + ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE)) != + cpu_to_le16(IEEE80211_STYPE_PSPOLL))) return 1; return 0; } @@ -79,8 +81,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, struct ieee80211_sub_if_data *sdata; struct ieee80211_rate *rate; int needed_headroom = 0; - struct ieee80211_rtap_hdr { - struct ieee80211_radiotap_header hdr; + struct ieee80211_radiotap_header *rthdr; + __le64 *rttsft = NULL; + struct ieee80211_rtap_fixed_data { u8 flags; u8 rate; __le16 chan_freq; @@ -88,7 +91,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, u8 antsignal; u8 padding_for_rxflags; __le16 rx_flags; - } __attribute__ ((packed)) *rthdr; + } __attribute__ ((packed)) *rtfixed; struct sk_buff *skb, *skb2; struct net_device *prev_dev = NULL; int present_fcs_len = 0; @@ -105,7 +108,8 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (status->flag & RX_FLAG_RADIOTAP) rtap_len = ieee80211_get_radiotap_len(origskb->data); else - needed_headroom = sizeof(*rthdr); + /* room for radiotap header, always present fields and TSFT */ + needed_headroom = sizeof(*rthdr) + sizeof(*rtfixed) + 8; if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) present_fcs_len = FCS_LEN; @@ -133,7 +137,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, * them allocate enough headroom to start with. */ if (skb_headroom(skb) < needed_headroom && - pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) { + pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); return NULL; } @@ -152,42 +156,56 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, /* if necessary, prepend radiotap information */ if (!(status->flag & RX_FLAG_RADIOTAP)) { + rtfixed = (void *) skb_push(skb, sizeof(*rtfixed)); + rtap_len = sizeof(*rthdr) + sizeof(*rtfixed); + if (status->flag & RX_FLAG_TSFT) { + rttsft = (void *) skb_push(skb, sizeof(*rttsft)); + rtap_len += 8; + } rthdr = (void *) skb_push(skb, sizeof(*rthdr)); memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = + memset(rtfixed, 0, sizeof(*rtfixed)); + rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); - rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ? - IEEE80211_RADIOTAP_F_FCS : 0; + rtfixed->flags = 0; + if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) + rtfixed->flags |= IEEE80211_RADIOTAP_F_FCS; + + if (rttsft) { + *rttsft = cpu_to_le64(status->mactime); + rthdr->it_present |= + cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); + } /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ - rthdr->rx_flags = 0; + rtfixed->rx_flags = 0; if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) - rthdr->rx_flags |= + rtfixed->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); rate = ieee80211_get_rate(local, status->phymode, status->rate); if (rate) - rthdr->rate = rate->rate / 5; + rtfixed->rate = rate->rate / 5; - rthdr->chan_freq = cpu_to_le16(status->freq); + rtfixed->chan_freq = cpu_to_le16(status->freq); if (status->phymode == MODE_IEEE80211A) - rthdr->chan_flags = + rtfixed->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ); else - rthdr->chan_flags = + rtfixed->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ); - rthdr->antsignal = status->ssi; + rtfixed->antsignal = status->ssi; + rthdr->it_len = cpu_to_le16(rtap_len); } skb_set_mac_header(skb, 0); @@ -243,6 +261,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN; /* frame has qos control */ tid = qc[0] & QOS_CONTROL_TID_MASK; + if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) + rx->flags |= IEEE80211_TXRXD_RX_AMSDU; + else + rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU; } else { if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { /* Separate TID for management frames */ @@ -338,8 +360,14 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; - if (unlikely(local->sta_scanning != 0)) { - ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); + if (unlikely(local->sta_hw_scanning)) + return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); + + if (unlikely(local->sta_sw_scanning)) { + /* drop all the other packets during a software scan anyway */ + if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status) + != TXRX_QUEUED) + dev_kfree_skb(skb); return TXRX_QUEUED; } @@ -870,6 +898,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) static ieee80211_txrx_result ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); struct sk_buff *skb; int no_pending_pkts; DECLARE_MAC_BUF(mac); @@ -880,6 +909,10 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) return TXRX_CONTINUE; + if ((sdata->type != IEEE80211_IF_TYPE_AP) && + (sdata->type != IEEE80211_IF_TYPE_VLAN)) + return TXRX_DROP; + skb = skb_dequeue(&rx->sta->tx_filtered); if (!skb) { skb = skb_dequeue(&rx->sta->ps_tx_buf); @@ -956,68 +989,64 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) return TXRX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx) +static int +ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen) { - if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) && + if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb, hdrlen) && rx->sdata->type != IEEE80211_IF_TYPE_STA && (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return 0; if (unlikely(rx->sdata->ieee802_1x && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && - !ieee80211_is_eapol(rx->skb))) { + !ieee80211_is_eapol(rx->skb, hdrlen))) { #ifdef CONFIG_MAC80211_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) rx->skb->data; - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: dropped frame from %s" - " (unauthorized port)\n", rx->dev->name, - print_mac(mac, hdr->addr2)); + printk(KERN_DEBUG "%s: dropped frame " + "(unauthorized port)\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return -EACCES; } - return TXRX_CONTINUE; + return 0; } -static ieee80211_txrx_result -ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx) +static int +ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen) { /* * Pass through unencrypted frames if the hardware has * decrypted them already. */ if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) - return TXRX_CONTINUE; + return 0; /* Drop unencrypted frames if key is set. */ if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && (rx->key || rx->sdata->drop_unencrypted) && - (rx->sdata->eapol == 0 || !ieee80211_is_eapol(rx->skb)))) { + (rx->sdata->eapol == 0 || + !ieee80211_is_eapol(rx->skb, hdrlen)))) { if (net_ratelimit()) printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " "encryption\n", rx->dev->name); - return TXRX_DROP; + return -EACCES; } - return TXRX_CONTINUE; + return 0; } -static ieee80211_txrx_result -ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +static int +ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) { struct net_device *dev = rx->dev; - struct ieee80211_local *local = rx->local; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc, hdrlen, ethertype; u8 *payload; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct sk_buff *skb = rx->skb, *skb2; + struct sk_buff *skb = rx->skb; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); @@ -1025,11 +1054,9 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) DECLARE_MAC_BUF(mac4); fc = rx->fc; - if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; + return -1; hdrlen = ieee80211_get_hdrlen(fc); @@ -1058,7 +1085,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) print_mac(mac, hdr->addr1), print_mac(mac2, hdr->addr2), print_mac(mac3, hdr->addr3)); - return TXRX_DROP; + return -1; } break; case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): @@ -1075,7 +1102,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) print_mac(mac2, hdr->addr2), print_mac(mac3, hdr->addr3), print_mac(mac4, hdr->addr4)); - return TXRX_DROP; + return -1; } break; case IEEE80211_FCTL_FROMDS: @@ -1086,7 +1113,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (sdata->type != IEEE80211_IF_TYPE_STA || (is_multicast_ether_addr(dst) && !compare_ether_addr(src, dev->dev_addr))) - return TXRX_DROP; + return -1; break; case 0: /* DA SA BSSID */ @@ -1102,21 +1129,20 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) print_mac(mac2, hdr->addr2), print_mac(mac3, hdr->addr3)); } - return TXRX_DROP; + return -1; } break; } - payload = skb->data + hdrlen; - if (unlikely(skb->len - hdrlen < 8)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: RX too short data frame " "payload\n", dev->name); } - return TXRX_DROP; + return -1; } + payload = skb->data + hdrlen; ethertype = (payload[6] << 8) | payload[7]; if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && @@ -1137,12 +1163,19 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) memcpy(ehdr->h_source, src, ETH_ALEN); ehdr->h_proto = len; } - skb->dev = dev; + return 0; +} - skb2 = NULL; +static void +ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) +{ + struct net_device *dev = rx->dev; + struct ieee80211_local *local = rx->local; + struct sk_buff *skb, *xmit_skb; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; + skb = rx->skb; + xmit_skb = NULL; if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP || sdata->type == IEEE80211_IF_TYPE_VLAN) && @@ -1150,8 +1183,8 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) if (is_multicast_ether_addr(skb->data)) { /* send multicast frames both to higher layers in * local net stack and back to the wireless media */ - skb2 = skb_copy(skb, GFP_ATOMIC); - if (!skb2 && net_ratelimit()) + xmit_skb = skb_copy(skb, GFP_ATOMIC); + if (!xmit_skb && net_ratelimit()) printk(KERN_DEBUG "%s: failed to clone " "multicast frame\n", dev->name); } else { @@ -1166,7 +1199,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) * AP, so send the frame directly to it and * do not pass the frame to local net stack. */ - skb2 = skb; + xmit_skb = skb; skb = NULL; } if (dsta) @@ -1181,17 +1214,168 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) netif_rx(skb); } - if (skb2) { + if (xmit_skb) { /* send to wireless media */ - skb2->protocol = __constant_htons(ETH_P_802_3); - skb_set_network_header(skb2, 0); - skb_set_mac_header(skb2, 0); - dev_queue_xmit(skb2); + xmit_skb->protocol = htons(ETH_P_802_3); + skb_set_network_header(xmit_skb, 0); + skb_set_mac_header(xmit_skb, 0); + dev_queue_xmit(xmit_skb); + } +} + +static ieee80211_txrx_result +ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) +{ + struct net_device *dev = rx->dev; + struct ieee80211_local *local = rx->local; + u16 fc, ethertype; + u8 *payload; + struct sk_buff *skb = rx->skb, *frame = NULL; + const struct ethhdr *eth; + int remaining, err; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + DECLARE_MAC_BUF(mac); + + fc = rx->fc; + if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) + return TXRX_CONTINUE; + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return TXRX_DROP; + + if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) + return TXRX_CONTINUE; + + err = ieee80211_data_to_8023(rx); + if (unlikely(err)) + return TXRX_DROP; + + skb->dev = dev; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + /* skip the wrapping header */ + eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); + if (!eth) + return TXRX_DROP; + + while (skb != frame) { + u8 padding; + __be16 len = eth->h_proto; + unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); + + remaining = skb->len; + memcpy(dst, eth->h_dest, ETH_ALEN); + memcpy(src, eth->h_source, ETH_ALEN); + + padding = ((4 - subframe_len) & 0x3); + /* the last MSDU has no padding */ + if (subframe_len > remaining) { + printk(KERN_DEBUG "%s: wrong buffer size", dev->name); + return TXRX_DROP; + } + + skb_pull(skb, sizeof(struct ethhdr)); + /* if last subframe reuse skb */ + if (remaining <= subframe_len + padding) + frame = skb; + else { + frame = dev_alloc_skb(local->hw.extra_tx_headroom + + subframe_len); + + if (frame == NULL) + return TXRX_DROP; + + skb_reserve(frame, local->hw.extra_tx_headroom + + sizeof(struct ethhdr)); + memcpy(skb_put(frame, ntohs(len)), skb->data, + ntohs(len)); + + eth = (struct ethhdr *) skb_pull(skb, ntohs(len) + + padding); + if (!eth) { + printk(KERN_DEBUG "%s: wrong buffer size ", + dev->name); + dev_kfree_skb(frame); + return TXRX_DROP; + } + } + + skb_set_network_header(frame, 0); + frame->dev = dev; + frame->priority = skb->priority; + rx->skb = frame; + + if ((ieee80211_drop_802_1x_pae(rx, 0)) || + (ieee80211_drop_unencrypted(rx, 0))) { + if (skb == frame) /* last frame */ + return TXRX_DROP; + dev_kfree_skb(frame); + continue; + } + + payload = frame->data; + ethertype = (payload[6] << 8) | payload[7]; + + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && + ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || + compare_ether_addr(payload, + bridge_tunnel_header) == 0)) { + /* remove RFC1042 or Bridge-Tunnel + * encapsulation and replace EtherType */ + skb_pull(frame, 6); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } else { + memcpy(skb_push(frame, sizeof(__be16)), &len, + sizeof(__be16)); + memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); + memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); + } + + + ieee80211_deliver_skb(rx); } return TXRX_QUEUED; } +static ieee80211_txrx_result +ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +{ + struct net_device *dev = rx->dev; + u16 fc; + int err, hdrlen; + + fc = rx->fc; + if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) + return TXRX_CONTINUE; + + if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) + return TXRX_DROP; + + hdrlen = ieee80211_get_hdrlen(fc); + + if ((ieee80211_drop_802_1x_pae(rx, hdrlen)) || + (ieee80211_drop_unencrypted(rx, hdrlen))) + return TXRX_DROP; + + err = ieee80211_data_to_8023(rx); + if (unlikely(err)) + return TXRX_DROP; + + rx->skb->dev = dev; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += rx->skb->len; + + ieee80211_deliver_skb(rx); + + return TXRX_QUEUED; +} + static ieee80211_txrx_result ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { @@ -1341,8 +1525,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = * are not passed to user space by these functions */ ieee80211_rx_h_remove_qos_control, - ieee80211_rx_h_802_1x_pae, - ieee80211_rx_h_drop_unencrypted, + ieee80211_rx_h_amsdu, ieee80211_rx_h_data, ieee80211_rx_h_mgmt, NULL @@ -1443,6 +1626,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_sub_if_data *prev = NULL; struct sk_buff *skb_new; u8 *bssid; + int hdrlen; /* * key references and virtual interfaces are protected using RCU @@ -1472,6 +1656,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; + /* + * Drivers are required to align the payload data to a four-byte + * boundary, so the last two bits of the address where it starts + * may not be set. The header is required to be directly before + * the payload data, padding like atheros hardware adds which is + * inbetween the 802.11 header and the payload is not supported, + * the driver is required to move the 802.11 header further back + * in that case. + */ + hdrlen = ieee80211_get_hdrlen(rx.fc); + WARN_ON_ONCE(((unsigned long)(skb->data + hdrlen)) & 3); + if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; @@ -1486,7 +1682,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, goto end; } - if (unlikely(local->sta_scanning)) + if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,