diff options
author | Zhu Yi <yi.zhu@intel.com> | 2006-04-13 05:19:11 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2006-04-24 16:15:54 -0400 |
commit | a5cf4fe65144ff2f35de37c7b58e7ab8ffd84d19 (patch) | |
tree | 405454d2816152c41e0e40d7846c9de18ae927d2 /drivers/net/wireless/ipw2200.c | |
parent | 00d21de5c685ab450ef376acdd1b733badb6b50d (diff) |
[PATCH] ipw2200: Fix TX QoS enabled frames problem
This patch works with the ieee80211 stack to set the correct QoS bit to the
ipw2200 card. It fixed the TX failure problem for using WPA with QoS.
Signed-off-by: Hong Liu <hong.liu@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ipw2200.c')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 71 |
1 files changed, 33 insertions, 38 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index a879edba5fac..0500e8006a14 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -6859,61 +6859,55 @@ static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority) | |||
6859 | return from_priority_to_tx_queue[priority] - 1; | 6859 | return from_priority_to_tx_queue[priority] - 1; |
6860 | } | 6860 | } |
6861 | 6861 | ||
6862 | /* | 6862 | static int ipw_is_qos_active(struct net_device *dev, |
6863 | * add QoS parameter to the TX command | 6863 | struct sk_buff *skb) |
6864 | */ | ||
6865 | static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, | ||
6866 | u16 priority, | ||
6867 | struct tfd_data *tfd, u8 unicast) | ||
6868 | { | 6864 | { |
6869 | int ret = 0; | 6865 | struct ipw_priv *priv = ieee80211_priv(dev); |
6870 | int tx_queue_id = 0; | ||
6871 | struct ieee80211_qos_data *qos_data = NULL; | 6866 | struct ieee80211_qos_data *qos_data = NULL; |
6872 | int active, supported; | 6867 | int active, supported; |
6873 | unsigned long flags; | 6868 | u8 *daddr = skb->data + ETH_ALEN; |
6869 | int unicast = !is_multicast_ether_addr(daddr); | ||
6874 | 6870 | ||
6875 | if (!(priv->status & STATUS_ASSOCIATED)) | 6871 | if (!(priv->status & STATUS_ASSOCIATED)) |
6876 | return 0; | 6872 | return 0; |
6877 | 6873 | ||
6878 | qos_data = &priv->assoc_network->qos_data; | 6874 | qos_data = &priv->assoc_network->qos_data; |
6879 | 6875 | ||
6880 | spin_lock_irqsave(&priv->ieee->lock, flags); | ||
6881 | |||
6882 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | 6876 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { |
6883 | if (unicast == 0) | 6877 | if (unicast == 0) |
6884 | qos_data->active = 0; | 6878 | qos_data->active = 0; |
6885 | else | 6879 | else |
6886 | qos_data->active = qos_data->supported; | 6880 | qos_data->active = qos_data->supported; |
6887 | } | 6881 | } |
6888 | |||
6889 | active = qos_data->active; | 6882 | active = qos_data->active; |
6890 | supported = qos_data->supported; | 6883 | supported = qos_data->supported; |
6891 | |||
6892 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | ||
6893 | |||
6894 | IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " | 6884 | IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " |
6895 | "unicast %d\n", | 6885 | "unicast %d\n", |
6896 | priv->qos_data.qos_enable, active, supported, unicast); | 6886 | priv->qos_data.qos_enable, active, supported, unicast); |
6897 | if (active && priv->qos_data.qos_enable) { | 6887 | if (active && priv->qos_data.qos_enable) |
6898 | ret = from_priority_to_tx_queue[priority]; | 6888 | return 1; |
6899 | tx_queue_id = ret - 1; | ||
6900 | IPW_DEBUG_QOS("QoS packet priority is %d \n", priority); | ||
6901 | if (priority <= 7) { | ||
6902 | tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; | ||
6903 | tfd->tfd.tfd_26.mchdr.qos_ctrl = priority; | ||
6904 | tfd->tfd.tfd_26.mchdr.frame_ctl |= | ||
6905 | IEEE80211_STYPE_QOS_DATA; | ||
6906 | |||
6907 | if (priv->qos_data.qos_no_ack_mask & | ||
6908 | (1UL << tx_queue_id)) { | ||
6909 | tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; | ||
6910 | tfd->tfd.tfd_26.mchdr.qos_ctrl |= | ||
6911 | CTRL_QOS_NO_ACK; | ||
6912 | } | ||
6913 | } | ||
6914 | } | ||
6915 | 6889 | ||
6916 | return ret; | 6890 | return 0; |
6891 | |||
6892 | } | ||
6893 | /* | ||
6894 | * add QoS parameter to the TX command | ||
6895 | */ | ||
6896 | static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, | ||
6897 | u16 priority, | ||
6898 | struct tfd_data *tfd) | ||
6899 | { | ||
6900 | int tx_queue_id = 0; | ||
6901 | |||
6902 | |||
6903 | tx_queue_id = from_priority_to_tx_queue[priority] - 1; | ||
6904 | tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED; | ||
6905 | |||
6906 | if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) { | ||
6907 | tfd->tx_flags &= ~DCT_FLAG_ACK_REQD; | ||
6908 | tfd->tfd.tfd_26.mchdr.qos_ctrl |= CTRL_QOS_NO_ACK; | ||
6909 | } | ||
6910 | return 0; | ||
6917 | } | 6911 | } |
6918 | 6912 | ||
6919 | /* | 6913 | /* |
@@ -9653,7 +9647,7 @@ we need to heavily modify the ieee80211_skb_to_txb. | |||
9653 | static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | 9647 | static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, |
9654 | int pri) | 9648 | int pri) |
9655 | { | 9649 | { |
9656 | struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *) | 9650 | struct ieee80211_hdr_3addrqos *hdr = (struct ieee80211_hdr_3addrqos *) |
9657 | txb->fragments[0]->data; | 9651 | txb->fragments[0]->data; |
9658 | int i = 0; | 9652 | int i = 0; |
9659 | struct tfd_frame *tfd; | 9653 | struct tfd_frame *tfd; |
@@ -9668,9 +9662,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | |||
9668 | u16 remaining_bytes; | 9662 | u16 remaining_bytes; |
9669 | int fc; | 9663 | int fc; |
9670 | 9664 | ||
9665 | hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | ||
9671 | switch (priv->ieee->iw_mode) { | 9666 | switch (priv->ieee->iw_mode) { |
9672 | case IW_MODE_ADHOC: | 9667 | case IW_MODE_ADHOC: |
9673 | hdr_len = IEEE80211_3ADDR_LEN; | ||
9674 | unicast = !is_multicast_ether_addr(hdr->addr1); | 9668 | unicast = !is_multicast_ether_addr(hdr->addr1); |
9675 | id = ipw_find_station(priv, hdr->addr1); | 9669 | id = ipw_find_station(priv, hdr->addr1); |
9676 | if (id == IPW_INVALID_STATION) { | 9670 | if (id == IPW_INVALID_STATION) { |
@@ -9687,7 +9681,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | |||
9687 | case IW_MODE_INFRA: | 9681 | case IW_MODE_INFRA: |
9688 | default: | 9682 | default: |
9689 | unicast = !is_multicast_ether_addr(hdr->addr3); | 9683 | unicast = !is_multicast_ether_addr(hdr->addr3); |
9690 | hdr_len = IEEE80211_3ADDR_LEN; | ||
9691 | id = 0; | 9684 | id = 0; |
9692 | break; | 9685 | break; |
9693 | } | 9686 | } |
@@ -9766,7 +9759,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | |||
9766 | tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP; | 9759 | tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP; |
9767 | 9760 | ||
9768 | #ifdef CONFIG_IPW_QOS | 9761 | #ifdef CONFIG_IPW_QOS |
9769 | ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data), unicast); | 9762 | if (fc & IEEE80211_STYPE_QOS_DATA) |
9763 | ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data)); | ||
9770 | #endif /* CONFIG_IPW_QOS */ | 9764 | #endif /* CONFIG_IPW_QOS */ |
9771 | 9765 | ||
9772 | /* payload */ | 9766 | /* payload */ |
@@ -10966,6 +10960,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
10966 | priv->ieee->is_queue_full = ipw_net_is_queue_full; | 10960 | priv->ieee->is_queue_full = ipw_net_is_queue_full; |
10967 | 10961 | ||
10968 | #ifdef CONFIG_IPW_QOS | 10962 | #ifdef CONFIG_IPW_QOS |
10963 | priv->ieee->is_qos_active = ipw_is_qos_active; | ||
10969 | priv->ieee->handle_probe_response = ipw_handle_beacon; | 10964 | priv->ieee->handle_probe_response = ipw_handle_beacon; |
10970 | priv->ieee->handle_beacon = ipw_handle_probe_response; | 10965 | priv->ieee->handle_beacon = ipw_handle_probe_response; |
10971 | priv->ieee->handle_assoc_response = ipw_handle_assoc_response; | 10966 | priv->ieee->handle_assoc_response = ipw_handle_assoc_response; |