diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/recv.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 194 |
1 files changed, 162 insertions, 32 deletions
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index b46badd21f73..5014a19b0f75 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -473,6 +473,159 @@ void ath_flushrecv(struct ath_softc *sc) | |||
473 | spin_unlock_bh(&sc->rx.rxflushlock); | 473 | spin_unlock_bh(&sc->rx.rxflushlock); |
474 | } | 474 | } |
475 | 475 | ||
476 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | ||
477 | { | ||
478 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ | ||
479 | struct ieee80211_mgmt *mgmt; | ||
480 | u8 *pos, *end, id, elen; | ||
481 | struct ieee80211_tim_ie *tim; | ||
482 | |||
483 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
484 | pos = mgmt->u.beacon.variable; | ||
485 | end = skb->data + skb->len; | ||
486 | |||
487 | while (pos + 2 < end) { | ||
488 | id = *pos++; | ||
489 | elen = *pos++; | ||
490 | if (pos + elen > end) | ||
491 | break; | ||
492 | |||
493 | if (id == WLAN_EID_TIM) { | ||
494 | if (elen < sizeof(*tim)) | ||
495 | break; | ||
496 | tim = (struct ieee80211_tim_ie *) pos; | ||
497 | if (tim->dtim_count != 0) | ||
498 | break; | ||
499 | return tim->bitmap_ctrl & 0x01; | ||
500 | } | ||
501 | |||
502 | pos += elen; | ||
503 | } | ||
504 | |||
505 | return false; | ||
506 | } | ||
507 | |||
508 | static void ath_rx_ps_back_to_sleep(struct ath_softc *sc) | ||
509 | { | ||
510 | sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); | ||
511 | } | ||
512 | |||
513 | static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) | ||
514 | { | ||
515 | struct ieee80211_mgmt *mgmt; | ||
516 | |||
517 | if (skb->len < 24 + 8 + 2 + 2) | ||
518 | return; | ||
519 | |||
520 | mgmt = (struct ieee80211_mgmt *)skb->data; | ||
521 | if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0) | ||
522 | return; /* not from our current AP */ | ||
523 | |||
524 | if (sc->sc_flags & SC_OP_BEACON_SYNC) { | ||
525 | sc->sc_flags &= ~SC_OP_BEACON_SYNC; | ||
526 | DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on " | ||
527 | "timestamp from the AP\n"); | ||
528 | ath_beacon_config(sc, NULL); | ||
529 | } | ||
530 | |||
531 | if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) { | ||
532 | /* We are not in PS mode anymore; remain awake */ | ||
533 | DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain " | ||
534 | "awake\n"); | ||
535 | sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB); | ||
536 | return; | ||
537 | } | ||
538 | |||
539 | if (ath_beacon_dtim_pending_cab(skb)) { | ||
540 | /* | ||
541 | * Remain awake waiting for buffered broadcast/multicast | ||
542 | * frames. | ||
543 | */ | ||
544 | DPRINTF(sc, ATH_DBG_PS, "Received DTIM beacon indicating " | ||
545 | "buffered broadcast/multicast frame(s)\n"); | ||
546 | sc->sc_flags |= SC_OP_WAIT_FOR_CAB; | ||
547 | return; | ||
548 | } | ||
549 | |||
550 | if (sc->sc_flags & SC_OP_WAIT_FOR_CAB) { | ||
551 | /* | ||
552 | * This can happen if a broadcast frame is dropped or the AP | ||
553 | * fails to send a frame indicating that all CAB frames have | ||
554 | * been delivered. | ||
555 | */ | ||
556 | DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n"); | ||
557 | } | ||
558 | |||
559 | /* No more broadcast/multicast frames to be received at this point. */ | ||
560 | ath_rx_ps_back_to_sleep(sc); | ||
561 | } | ||
562 | |||
563 | static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) | ||
564 | { | ||
565 | struct ieee80211_hdr *hdr; | ||
566 | |||
567 | hdr = (struct ieee80211_hdr *)skb->data; | ||
568 | |||
569 | /* Process Beacon and CAB receive in PS state */ | ||
570 | if ((sc->sc_flags & SC_OP_WAIT_FOR_BEACON) && | ||
571 | ieee80211_is_beacon(hdr->frame_control)) | ||
572 | ath_rx_ps_beacon(sc, skb); | ||
573 | else if ((sc->sc_flags & SC_OP_WAIT_FOR_CAB) && | ||
574 | (ieee80211_is_data(hdr->frame_control) || | ||
575 | ieee80211_is_action(hdr->frame_control)) && | ||
576 | is_multicast_ether_addr(hdr->addr1) && | ||
577 | !ieee80211_has_moredata(hdr->frame_control)) { | ||
578 | DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to " | ||
579 | "sleep\n"); | ||
580 | /* | ||
581 | * No more broadcast/multicast frames to be received at this | ||
582 | * point. | ||
583 | */ | ||
584 | ath_rx_ps_back_to_sleep(sc); | ||
585 | } else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) && | ||
586 | !is_multicast_ether_addr(hdr->addr1) && | ||
587 | !ieee80211_has_morefrags(hdr->frame_control)) { | ||
588 | sc->sc_flags &= ~SC_OP_WAIT_FOR_PSPOLL_DATA; | ||
589 | DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having " | ||
590 | "received PS-Poll data (0x%x)\n", | ||
591 | sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | | ||
592 | SC_OP_WAIT_FOR_CAB | | ||
593 | SC_OP_WAIT_FOR_PSPOLL_DATA | | ||
594 | SC_OP_WAIT_FOR_TX_ACK)); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb, | ||
599 | struct ieee80211_rx_status *rx_status) | ||
600 | { | ||
601 | struct ieee80211_hdr *hdr; | ||
602 | |||
603 | hdr = (struct ieee80211_hdr *)skb->data; | ||
604 | |||
605 | /* Send the frame to mac80211 */ | ||
606 | if (is_multicast_ether_addr(hdr->addr1)) { | ||
607 | int i; | ||
608 | /* | ||
609 | * Deliver broadcast/multicast frames to all suitable | ||
610 | * virtual wiphys. | ||
611 | */ | ||
612 | /* TODO: filter based on channel configuration */ | ||
613 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
614 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
615 | struct sk_buff *nskb; | ||
616 | if (aphy == NULL) | ||
617 | continue; | ||
618 | nskb = skb_copy(skb, GFP_ATOMIC); | ||
619 | if (nskb) | ||
620 | __ieee80211_rx(aphy->hw, nskb, rx_status); | ||
621 | } | ||
622 | __ieee80211_rx(sc->hw, skb, rx_status); | ||
623 | } else { | ||
624 | /* Deliver unicast frames based on receiver address */ | ||
625 | __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status); | ||
626 | } | ||
627 | } | ||
628 | |||
476 | int ath_rx_tasklet(struct ath_softc *sc, int flush) | 629 | int ath_rx_tasklet(struct ath_softc *sc, int flush) |
477 | { | 630 | { |
478 | #define PA2DESC(_sc, _pa) \ | 631 | #define PA2DESC(_sc, _pa) \ |
@@ -622,7 +775,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
622 | 775 | ||
623 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { | 776 | if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { |
624 | rx_status.flag |= RX_FLAG_DECRYPTED; | 777 | rx_status.flag |= RX_FLAG_DECRYPTED; |
625 | } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) | 778 | } else if (ieee80211_has_protected(fc) |
626 | && !decrypt_error && skb->len >= hdrlen + 4) { | 779 | && !decrypt_error && skb->len >= hdrlen + 4) { |
627 | keyix = skb->data[hdrlen + 3] >> 6; | 780 | keyix = skb->data[hdrlen + 3] >> 6; |
628 | 781 | ||
@@ -631,36 +784,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
631 | } | 784 | } |
632 | if (ah->sw_mgmt_crypto && | 785 | if (ah->sw_mgmt_crypto && |
633 | (rx_status.flag & RX_FLAG_DECRYPTED) && | 786 | (rx_status.flag & RX_FLAG_DECRYPTED) && |
634 | ieee80211_is_mgmt(hdr->frame_control)) { | 787 | ieee80211_is_mgmt(fc)) { |
635 | /* Use software decrypt for management frames. */ | 788 | /* Use software decrypt for management frames. */ |
636 | rx_status.flag &= ~RX_FLAG_DECRYPTED; | 789 | rx_status.flag &= ~RX_FLAG_DECRYPTED; |
637 | } | 790 | } |
638 | 791 | ||
639 | /* Send the frame to mac80211 */ | ||
640 | if (hdr->addr1[5] & 0x01) { | ||
641 | int i; | ||
642 | /* | ||
643 | * Deliver broadcast/multicast frames to all suitable | ||
644 | * virtual wiphys. | ||
645 | */ | ||
646 | /* TODO: filter based on channel configuration */ | ||
647 | for (i = 0; i < sc->num_sec_wiphy; i++) { | ||
648 | struct ath_wiphy *aphy = sc->sec_wiphy[i]; | ||
649 | struct sk_buff *nskb; | ||
650 | if (aphy == NULL) | ||
651 | continue; | ||
652 | nskb = skb_copy(skb, GFP_ATOMIC); | ||
653 | if (nskb) | ||
654 | __ieee80211_rx(aphy->hw, nskb, | ||
655 | &rx_status); | ||
656 | } | ||
657 | __ieee80211_rx(sc->hw, skb, &rx_status); | ||
658 | } else { | ||
659 | /* Deliver unicast frames based on receiver address */ | ||
660 | __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, | ||
661 | &rx_status); | ||
662 | } | ||
663 | |||
664 | /* We will now give hardware our shiny new allocated skb */ | 792 | /* We will now give hardware our shiny new allocated skb */ |
665 | bf->bf_mpdu = requeue_skb; | 793 | bf->bf_mpdu = requeue_skb; |
666 | bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, | 794 | bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data, |
@@ -672,6 +800,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
672 | bf->bf_mpdu = NULL; | 800 | bf->bf_mpdu = NULL; |
673 | DPRINTF(sc, ATH_DBG_FATAL, | 801 | DPRINTF(sc, ATH_DBG_FATAL, |
674 | "dma_mapping_error() on RX\n"); | 802 | "dma_mapping_error() on RX\n"); |
803 | ath_rx_send_to_mac80211(sc, skb, &rx_status); | ||
675 | break; | 804 | break; |
676 | } | 805 | } |
677 | bf->bf_dmacontext = bf->bf_buf_addr; | 806 | bf->bf_dmacontext = bf->bf_buf_addr; |
@@ -687,11 +816,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) | |||
687 | sc->rx.rxotherant = 0; | 816 | sc->rx.rxotherant = 0; |
688 | } | 817 | } |
689 | 818 | ||
690 | if (ieee80211_is_beacon(fc) && | 819 | if (unlikely(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON | |
691 | (sc->sc_flags & SC_OP_WAIT_FOR_BEACON)) { | 820 | SC_OP_WAIT_FOR_PSPOLL_DATA))) |
692 | sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON; | 821 | ath_rx_ps(sc, skb); |
693 | ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); | 822 | |
694 | } | 823 | ath_rx_send_to_mac80211(sc, skb, &rx_status); |
824 | |||
695 | requeue: | 825 | requeue: |
696 | list_move_tail(&bf->list, &sc->rx.rxbuf); | 826 | list_move_tail(&bf->list, &sc->rx.rxbuf); |
697 | ath_rx_buf_link(sc, bf); | 827 | ath_rx_buf_link(sc, bf); |