diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-09-21 12:56:33 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-21 23:03:54 -0400 |
commit | 9e8571affd1c54b9638b4ff9844e47aae07310f6 (patch) | |
tree | f6e568913c2d8aa1bf6bfedb3d90a78f2ade747b | |
parent | 2c0aa2a5c2dfa1293ae3a07517d0b7de149358a1 (diff) |
[PATCH] ieee80211: Add QoS (WME) support to the ieee80211 subsystem
tree a3ad796273e98036eb0e9fc063225070fa24508a
parent 1b9c0aeb377abf8e4a43a86cff42382f74ca0259
author Mohamed Abbas <mabbas@linux.intel.com> 1124447069 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127313435 -0500
Add QoS (WME) support to the ieee80211 subsystem.
NOTE: This requires drivers that use the ieee80211 hard_start_xmit
(ipw2100 and ipw2200) to add the priority parameter to their callback.
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | include/net/ieee80211.h | 103 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 334 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 5 |
3 files changed, 417 insertions, 25 deletions
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 46466f5a2b45..72bd2b17eeb4 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h | |||
@@ -92,6 +92,7 @@ | |||
92 | #define IEEE80211_STYPE_CFACK 0x0050 | 92 | #define IEEE80211_STYPE_CFACK 0x0050 |
93 | #define IEEE80211_STYPE_CFPOLL 0x0060 | 93 | #define IEEE80211_STYPE_CFPOLL 0x0060 |
94 | #define IEEE80211_STYPE_CFACKPOLL 0x0070 | 94 | #define IEEE80211_STYPE_CFACKPOLL 0x0070 |
95 | #define IEEE80211_STYPE_QOS_DATA 0x0080 | ||
95 | 96 | ||
96 | #define IEEE80211_SCTL_FRAG 0x000F | 97 | #define IEEE80211_SCTL_FRAG 0x000F |
97 | #define IEEE80211_SCTL_SEQ 0xFFF0 | 98 | #define IEEE80211_SCTL_SEQ 0xFFF0 |
@@ -153,6 +154,7 @@ const char *escape_essid(const char *essid, u8 essid_len); | |||
153 | 154 | ||
154 | #define IEEE80211_DL_TX (1<<8) | 155 | #define IEEE80211_DL_TX (1<<8) |
155 | #define IEEE80211_DL_RX (1<<9) | 156 | #define IEEE80211_DL_RX (1<<9) |
157 | #define IEEE80211_DL_QOS (1<<31) | ||
156 | 158 | ||
157 | #define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) | 159 | #define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) |
158 | #define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) | 160 | #define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) |
@@ -166,6 +168,7 @@ const char *escape_essid(const char *essid, u8 essid_len); | |||
166 | #define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) | 168 | #define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) |
167 | #define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) | 169 | #define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) |
168 | #define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) | 170 | #define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) |
171 | #define IEEE80211_DEBUG_QOS(f, a...) IEEE80211_DEBUG(IEEE80211_DL_QOS, f, ## a) | ||
169 | #include <linux/netdevice.h> | 172 | #include <linux/netdevice.h> |
170 | #include <linux/wireless.h> | 173 | #include <linux/wireless.h> |
171 | #include <linux/if_arp.h> /* ARPHRD_ETHER */ | 174 | #include <linux/if_arp.h> /* ARPHRD_ETHER */ |
@@ -493,6 +496,7 @@ enum ieee80211_mfie { | |||
493 | MFIE_TYPE_RSN = 48, | 496 | MFIE_TYPE_RSN = 48, |
494 | MFIE_TYPE_RATES_EX = 50, | 497 | MFIE_TYPE_RATES_EX = 50, |
495 | MFIE_TYPE_GENERIC = 221, | 498 | MFIE_TYPE_GENERIC = 221, |
499 | MFIE_TYPE_QOS_PARAMETER = 222, | ||
496 | }; | 500 | }; |
497 | 501 | ||
498 | /* Minimal header; can be used for passing 802.11 frames with sufficient | 502 | /* Minimal header; can be used for passing 802.11 frames with sufficient |
@@ -540,6 +544,29 @@ struct ieee80211_hdr_4addr { | |||
540 | u8 payload[0]; | 544 | u8 payload[0]; |
541 | } __attribute__ ((packed)); | 545 | } __attribute__ ((packed)); |
542 | 546 | ||
547 | struct ieee80211_hdr_3addrqos { | ||
548 | u16 frame_ctl; | ||
549 | u16 duration_id; | ||
550 | u8 addr1[ETH_ALEN]; | ||
551 | u8 addr2[ETH_ALEN]; | ||
552 | u8 addr3[ETH_ALEN]; | ||
553 | u16 seq_ctl; | ||
554 | u8 payload[0]; | ||
555 | u16 qos_ctl; | ||
556 | } __attribute__ ((packed)); | ||
557 | |||
558 | struct ieee80211_hdr_4addrqos { | ||
559 | u16 frame_ctl; | ||
560 | u16 duration_id; | ||
561 | u8 addr1[ETH_ALEN]; | ||
562 | u8 addr2[ETH_ALEN]; | ||
563 | u8 addr3[ETH_ALEN]; | ||
564 | u16 seq_ctl; | ||
565 | u8 addr4[ETH_ALEN]; | ||
566 | u8 payload[0]; | ||
567 | u16 qos_ctl; | ||
568 | } __attribute__ ((packed)); | ||
569 | |||
543 | struct ieee80211_info_element { | 570 | struct ieee80211_info_element { |
544 | u8 id; | 571 | u8 id; |
545 | u8 len; | 572 | u8 len; |
@@ -641,9 +668,68 @@ struct ieee80211_txb { | |||
641 | 668 | ||
642 | #define MAX_WPA_IE_LEN 64 | 669 | #define MAX_WPA_IE_LEN 64 |
643 | 670 | ||
644 | #define NETWORK_EMPTY_ESSID (1<<0) | 671 | #define NETWORK_EMPTY_ESSID (1<<0) |
645 | #define NETWORK_HAS_OFDM (1<<1) | 672 | #define NETWORK_HAS_OFDM (1<<1) |
646 | #define NETWORK_HAS_CCK (1<<2) | 673 | #define NETWORK_HAS_CCK (1<<2) |
674 | |||
675 | /* QoS structure */ | ||
676 | #define NETWORK_HAS_QOS_PARAMETERS (1<<3) | ||
677 | #define NETWORK_HAS_QOS_INFORMATION (1<<4) | ||
678 | #define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | NETWORK_HAS_QOS_INFORMATION) | ||
679 | |||
680 | #define QOS_QUEUE_NUM 4 | ||
681 | #define QOS_OUI_LEN 3 | ||
682 | #define QOS_OUI_TYPE 2 | ||
683 | #define QOS_ELEMENT_ID 221 | ||
684 | #define QOS_OUI_INFO_SUB_TYPE 0 | ||
685 | #define QOS_OUI_PARAM_SUB_TYPE 1 | ||
686 | #define QOS_VERSION_1 1 | ||
687 | #define QOS_AIFSN_MIN_VALUE 2 | ||
688 | |||
689 | struct ieee80211_qos_information_element { | ||
690 | u8 elementID; | ||
691 | u8 length; | ||
692 | u8 qui[QOS_OUI_LEN]; | ||
693 | u8 qui_type; | ||
694 | u8 qui_subtype; | ||
695 | u8 version; | ||
696 | u8 ac_info; | ||
697 | } __attribute__ ((packed)); | ||
698 | |||
699 | struct ieee80211_qos_ac_parameter { | ||
700 | u8 aci_aifsn; | ||
701 | u8 ecw_min_max; | ||
702 | u16 tx_op_limit; | ||
703 | } __attribute__ ((packed)); | ||
704 | |||
705 | struct ieee80211_qos_parameter_info { | ||
706 | struct ieee80211_qos_information_element info_element; | ||
707 | u8 reserved; | ||
708 | struct ieee80211_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM]; | ||
709 | } __attribute__ ((packed)); | ||
710 | |||
711 | struct ieee80211_qos_parameters { | ||
712 | u16 cw_min[QOS_QUEUE_NUM]; | ||
713 | u16 cw_max[QOS_QUEUE_NUM]; | ||
714 | u8 aifs[QOS_QUEUE_NUM]; | ||
715 | u8 flag[QOS_QUEUE_NUM]; | ||
716 | u16 tx_op_limit[QOS_QUEUE_NUM]; | ||
717 | } __attribute__ ((packed)); | ||
718 | |||
719 | struct ieee80211_qos_data { | ||
720 | struct ieee80211_qos_parameters parameters; | ||
721 | int active; | ||
722 | int supported; | ||
723 | u8 param_count; | ||
724 | u8 old_param_count; | ||
725 | }; | ||
726 | |||
727 | struct ieee80211_tim_parameters { | ||
728 | u8 tim_count; | ||
729 | u8 tim_period; | ||
730 | } __attribute__ ((packed)); | ||
731 | |||
732 | /*******************************************************/ | ||
647 | 733 | ||
648 | struct ieee80211_network { | 734 | struct ieee80211_network { |
649 | /* These entries are used to identify a unique network */ | 735 | /* These entries are used to identify a unique network */ |
@@ -653,6 +739,8 @@ struct ieee80211_network { | |||
653 | u8 ssid[IW_ESSID_MAX_SIZE + 1]; | 739 | u8 ssid[IW_ESSID_MAX_SIZE + 1]; |
654 | u8 ssid_len; | 740 | u8 ssid_len; |
655 | 741 | ||
742 | struct ieee80211_qos_data qos_data; | ||
743 | |||
656 | /* These are network statistics */ | 744 | /* These are network statistics */ |
657 | struct ieee80211_rx_stats stats; | 745 | struct ieee80211_rx_stats stats; |
658 | u16 capability; | 746 | u16 capability; |
@@ -672,6 +760,7 @@ struct ieee80211_network { | |||
672 | size_t wpa_ie_len; | 760 | size_t wpa_ie_len; |
673 | u8 rsn_ie[MAX_WPA_IE_LEN]; | 761 | u8 rsn_ie[MAX_WPA_IE_LEN]; |
674 | size_t rsn_ie_len; | 762 | size_t rsn_ie_len; |
763 | struct ieee80211_tim_parameters tim; | ||
675 | struct list_head list; | 764 | struct list_head list; |
676 | }; | 765 | }; |
677 | 766 | ||
@@ -769,10 +858,13 @@ struct ieee80211_device { | |||
769 | void (*set_security) (struct net_device * dev, | 858 | void (*set_security) (struct net_device * dev, |
770 | struct ieee80211_security * sec); | 859 | struct ieee80211_security * sec); |
771 | int (*hard_start_xmit) (struct ieee80211_txb * txb, | 860 | int (*hard_start_xmit) (struct ieee80211_txb * txb, |
772 | struct net_device * dev); | 861 | struct net_device * dev, int pri); |
773 | int (*reset_port) (struct net_device * dev); | 862 | int (*reset_port) (struct net_device * dev); |
774 | int (*is_queue_full) (struct net_device * dev, int pri); | 863 | int (*is_queue_full) (struct net_device * dev, int pri); |
775 | 864 | ||
865 | int (*handle_management) (struct net_device * dev, | ||
866 | struct ieee80211_network * network, u16 type); | ||
867 | |||
776 | /* Typical STA methods */ | 868 | /* Typical STA methods */ |
777 | int (*handle_auth) (struct net_device * dev, | 869 | int (*handle_auth) (struct net_device * dev, |
778 | struct ieee80211_auth * auth); | 870 | struct ieee80211_auth * auth); |
@@ -854,11 +946,14 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, | |||
854 | extern inline int ieee80211_get_hdrlen(u16 fc) | 946 | extern inline int ieee80211_get_hdrlen(u16 fc) |
855 | { | 947 | { |
856 | int hdrlen = IEEE80211_3ADDR_LEN; | 948 | int hdrlen = IEEE80211_3ADDR_LEN; |
949 | u16 stype = WLAN_FC_GET_STYPE(fc); | ||
857 | 950 | ||
858 | switch (WLAN_FC_GET_TYPE(fc)) { | 951 | switch (WLAN_FC_GET_TYPE(fc)) { |
859 | case IEEE80211_FTYPE_DATA: | 952 | case IEEE80211_FTYPE_DATA: |
860 | if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) | 953 | if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) |
861 | hdrlen = IEEE80211_4ADDR_LEN; | 954 | hdrlen = IEEE80211_4ADDR_LEN; |
955 | if (stype & IEEE80211_STYPE_QOS_DATA) | ||
956 | hdrlen += 2; | ||
862 | break; | 957 | break; |
863 | case IEEE80211_FTYPE_CTL: | 958 | case IEEE80211_FTYPE_CTL: |
864 | switch (WLAN_FC_GET_STYPE(fc)) { | 959 | switch (WLAN_FC_GET_STYPE(fc)) { |
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index d1ae28280d7e..2c4613527dfd 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c | |||
@@ -534,6 +534,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
534 | 534 | ||
535 | /* Nullfunc frames may have PS-bit set, so they must be passed to | 535 | /* Nullfunc frames may have PS-bit set, so they must be passed to |
536 | * hostap_handle_sta_rx() before being dropped here. */ | 536 | * hostap_handle_sta_rx() before being dropped here. */ |
537 | |||
538 | stype &= ~IEEE80211_STYPE_QOS_DATA; | ||
539 | |||
537 | if (stype != IEEE80211_STYPE_DATA && | 540 | if (stype != IEEE80211_STYPE_DATA && |
538 | stype != IEEE80211_STYPE_DATA_CFACK && | 541 | stype != IEEE80211_STYPE_DATA_CFACK && |
539 | stype != IEEE80211_STYPE_DATA_CFPOLL && | 542 | stype != IEEE80211_STYPE_DATA_CFPOLL && |
@@ -758,6 +761,264 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
758 | 761 | ||
759 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 | 762 | #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 |
760 | 763 | ||
764 | static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; | ||
765 | |||
766 | /* | ||
767 | * Make ther structure we read from the beacon packet has | ||
768 | * the right values | ||
769 | */ | ||
770 | static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element | ||
771 | *info_element, int sub_type) | ||
772 | { | ||
773 | |||
774 | if (info_element->qui_subtype != sub_type) | ||
775 | return -1; | ||
776 | if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN)) | ||
777 | return -1; | ||
778 | if (info_element->qui_type != QOS_OUI_TYPE) | ||
779 | return -1; | ||
780 | if (info_element->version != QOS_VERSION_1) | ||
781 | return -1; | ||
782 | |||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | /* | ||
787 | * Parse a QoS parameter element | ||
788 | */ | ||
789 | static int ieee80211_read_qos_param_element(struct ieee80211_qos_parameter_info | ||
790 | *element_param, struct ieee80211_info_element | ||
791 | *info_element) | ||
792 | { | ||
793 | int ret = 0; | ||
794 | u16 size = sizeof(struct ieee80211_qos_parameter_info) - 2; | ||
795 | |||
796 | if ((info_element == NULL) || (element_param == NULL)) | ||
797 | return -1; | ||
798 | |||
799 | if (info_element->id == QOS_ELEMENT_ID && info_element->len == size) { | ||
800 | memcpy(element_param->info_element.qui, info_element->data, | ||
801 | info_element->len); | ||
802 | element_param->info_element.elementID = info_element->id; | ||
803 | element_param->info_element.length = info_element->len; | ||
804 | } else | ||
805 | ret = -1; | ||
806 | if (ret == 0) | ||
807 | ret = ieee80211_verify_qos_info(&element_param->info_element, | ||
808 | QOS_OUI_PARAM_SUB_TYPE); | ||
809 | return ret; | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * Parse a QoS information element | ||
814 | */ | ||
815 | static int ieee80211_read_qos_info_element(struct | ||
816 | ieee80211_qos_information_element | ||
817 | *element_info, struct ieee80211_info_element | ||
818 | *info_element) | ||
819 | { | ||
820 | int ret = 0; | ||
821 | u16 size = sizeof(struct ieee80211_qos_information_element) - 2; | ||
822 | |||
823 | if (element_info == NULL) | ||
824 | return -1; | ||
825 | if (info_element == NULL) | ||
826 | return -1; | ||
827 | |||
828 | if ((info_element->id == QOS_ELEMENT_ID) && (info_element->len == size)) { | ||
829 | memcpy(element_info->qui, info_element->data, | ||
830 | info_element->len); | ||
831 | element_info->elementID = info_element->id; | ||
832 | element_info->length = info_element->len; | ||
833 | } else | ||
834 | ret = -1; | ||
835 | |||
836 | if (ret == 0) | ||
837 | ret = ieee80211_verify_qos_info(element_info, | ||
838 | QOS_OUI_INFO_SUB_TYPE); | ||
839 | return ret; | ||
840 | } | ||
841 | |||
842 | /* | ||
843 | * Write QoS parameters from the ac parameters. | ||
844 | */ | ||
845 | static int ieee80211_qos_convert_ac_to_parameters(struct | ||
846 | ieee80211_qos_parameter_info | ||
847 | *param_elm, struct | ||
848 | ieee80211_qos_parameters | ||
849 | *qos_param) | ||
850 | { | ||
851 | int rc = 0; | ||
852 | int i; | ||
853 | struct ieee80211_qos_ac_parameter *ac_params; | ||
854 | u32 txop; | ||
855 | u8 cw_min; | ||
856 | u8 cw_max; | ||
857 | |||
858 | for (i = 0; i < QOS_QUEUE_NUM; i++) { | ||
859 | ac_params = &(param_elm->ac_params_record[i]); | ||
860 | |||
861 | qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F; | ||
862 | qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2; | ||
863 | |||
864 | cw_min = ac_params->ecw_min_max & 0x0F; | ||
865 | qos_param->cw_min[i] = (u16) ((1 << cw_min) - 1); | ||
866 | |||
867 | cw_max = (ac_params->ecw_min_max & 0xF0) >> 4; | ||
868 | qos_param->cw_max[i] = (u16) ((1 << cw_max) - 1); | ||
869 | |||
870 | qos_param->flag[i] = | ||
871 | (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00; | ||
872 | |||
873 | txop = le16_to_cpu(ac_params->tx_op_limit) * 32; | ||
874 | qos_param->tx_op_limit[i] = (u16) txop; | ||
875 | } | ||
876 | return rc; | ||
877 | } | ||
878 | |||
879 | /* | ||
880 | * we have a generic data element which it may contain QoS information or | ||
881 | * parameters element. check the information element length to decide | ||
882 | * which type to read | ||
883 | */ | ||
884 | static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element | ||
885 | *info_element, | ||
886 | struct ieee80211_network *network) | ||
887 | { | ||
888 | int rc = 0; | ||
889 | struct ieee80211_qos_parameters *qos_param = NULL; | ||
890 | struct ieee80211_qos_information_element qos_info_element; | ||
891 | |||
892 | rc = ieee80211_read_qos_info_element(&qos_info_element, info_element); | ||
893 | |||
894 | if (rc == 0) { | ||
895 | network->qos_data.param_count = qos_info_element.ac_info & 0x0F; | ||
896 | network->flags |= NETWORK_HAS_QOS_INFORMATION; | ||
897 | } else { | ||
898 | struct ieee80211_qos_parameter_info param_element; | ||
899 | |||
900 | rc = ieee80211_read_qos_param_element(¶m_element, | ||
901 | info_element); | ||
902 | if (rc == 0) { | ||
903 | qos_param = &(network->qos_data.parameters); | ||
904 | ieee80211_qos_convert_ac_to_parameters(¶m_element, | ||
905 | qos_param); | ||
906 | network->flags |= NETWORK_HAS_QOS_PARAMETERS; | ||
907 | network->qos_data.param_count = | ||
908 | param_element.info_element.ac_info & 0x0F; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | if (rc == 0) { | ||
913 | IEEE80211_DEBUG_QOS("QoS is supported\n"); | ||
914 | network->qos_data.supported = 1; | ||
915 | } | ||
916 | return rc; | ||
917 | } | ||
918 | |||
919 | static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response | ||
920 | *frame, struct ieee80211_rx_stats *stats) | ||
921 | { | ||
922 | struct ieee80211_network network_resp; | ||
923 | struct ieee80211_network *network = &network_resp; | ||
924 | struct ieee80211_info_element *info_element; | ||
925 | struct net_device *dev = ieee->dev; | ||
926 | u16 left; | ||
927 | |||
928 | network->flags = 0; | ||
929 | network->qos_data.active = 0; | ||
930 | network->qos_data.supported = 0; | ||
931 | network->qos_data.param_count = 0; | ||
932 | network->qos_data.old_param_count = 0; | ||
933 | |||
934 | //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF); | ||
935 | network->atim_window = le16_to_cpu(frame->aid); | ||
936 | network->listen_interval = le16_to_cpu(frame->status); | ||
937 | |||
938 | info_element = frame->info_element; | ||
939 | left = stats->len - sizeof(*frame); | ||
940 | |||
941 | while (left >= sizeof(struct ieee80211_info_element)) { | ||
942 | if (sizeof(struct ieee80211_info_element) + | ||
943 | info_element->len > left) { | ||
944 | IEEE80211_DEBUG_QOS("ASSOC RESP: parse failed: " | ||
945 | "info_element->len + 2 > left : " | ||
946 | "info_element->len+2=%zd left=%d, id=%d.\n", | ||
947 | info_element->len + | ||
948 | sizeof(struct | ||
949 | ieee80211_info_element), | ||
950 | left, info_element->id); | ||
951 | return 1; | ||
952 | } | ||
953 | |||
954 | switch (info_element->id) { | ||
955 | case MFIE_TYPE_SSID: | ||
956 | if (ieee80211_is_empty_essid(info_element->data, | ||
957 | info_element->len)) { | ||
958 | network->flags |= NETWORK_EMPTY_ESSID; | ||
959 | break; | ||
960 | } | ||
961 | |||
962 | network->ssid_len = min(info_element->len, | ||
963 | (u8) IW_ESSID_MAX_SIZE); | ||
964 | memcpy(network->ssid, info_element->data, | ||
965 | network->ssid_len); | ||
966 | if (network->ssid_len < IW_ESSID_MAX_SIZE) | ||
967 | memset(network->ssid + network->ssid_len, 0, | ||
968 | IW_ESSID_MAX_SIZE - network->ssid_len); | ||
969 | |||
970 | IEEE80211_DEBUG_QOS("MFIE_TYPE_SSID: '%s' len=%d.\n", | ||
971 | network->ssid, network->ssid_len); | ||
972 | break; | ||
973 | |||
974 | case MFIE_TYPE_TIM: | ||
975 | IEEE80211_DEBUG_QOS("MFIE_TYPE_TIM: ignored\n"); | ||
976 | break; | ||
977 | |||
978 | case MFIE_TYPE_IBSS_SET: | ||
979 | IEEE80211_DEBUG_QOS("MFIE_TYPE_IBSS_SET: ignored\n"); | ||
980 | break; | ||
981 | |||
982 | case MFIE_TYPE_CHALLENGE: | ||
983 | IEEE80211_DEBUG_QOS("MFIE_TYPE_CHALLENGE: ignored\n"); | ||
984 | break; | ||
985 | |||
986 | case MFIE_TYPE_GENERIC: | ||
987 | IEEE80211_DEBUG_QOS("MFIE_TYPE_GENERIC: %d bytes\n", | ||
988 | info_element->len); | ||
989 | ieee80211_parse_qos_info_param_IE(info_element, | ||
990 | network); | ||
991 | break; | ||
992 | |||
993 | case MFIE_TYPE_RSN: | ||
994 | IEEE80211_DEBUG_QOS("MFIE_TYPE_RSN: %d bytes\n", | ||
995 | info_element->len); | ||
996 | break; | ||
997 | |||
998 | case MFIE_TYPE_QOS_PARAMETER: | ||
999 | printk("QoS Error need to parse QOS_PARAMETER IE\n"); | ||
1000 | break; | ||
1001 | |||
1002 | default: | ||
1003 | IEEE80211_DEBUG_QOS("unsupported IE %d\n", | ||
1004 | info_element->id); | ||
1005 | break; | ||
1006 | } | ||
1007 | |||
1008 | left -= sizeof(struct ieee80211_info_element) + | ||
1009 | info_element->len; | ||
1010 | info_element = (struct ieee80211_info_element *) | ||
1011 | &info_element->data[info_element->len]; | ||
1012 | } | ||
1013 | |||
1014 | if (ieee->handle_assoc_response != NULL) | ||
1015 | ieee->handle_assoc_response(dev, frame, network); | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | /***************************************************/ | ||
1021 | |||
761 | static inline int ieee80211_is_ofdm_rate(u8 rate) | 1022 | static inline int ieee80211_is_ofdm_rate(u8 rate) |
762 | { | 1023 | { |
763 | switch (rate & ~IEEE80211_BASIC_RATE_MASK) { | 1024 | switch (rate & ~IEEE80211_BASIC_RATE_MASK) { |
@@ -786,6 +1047,9 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i | |||
786 | struct ieee80211_info_element *info_element; | 1047 | struct ieee80211_info_element *info_element; |
787 | u16 left; | 1048 | u16 left; |
788 | u8 i; | 1049 | u8 i; |
1050 | network->qos_data.active = 0; | ||
1051 | network->qos_data.supported = 0; | ||
1052 | network->qos_data.param_count = 0; | ||
789 | 1053 | ||
790 | /* Pull out fixed field data */ | 1054 | /* Pull out fixed field data */ |
791 | memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); | 1055 | memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); |
@@ -813,13 +1077,11 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i | |||
813 | 1077 | ||
814 | info_element = beacon->info_element; | 1078 | info_element = beacon->info_element; |
815 | left = stats->len - sizeof(*beacon); | 1079 | left = stats->len - sizeof(*beacon); |
816 | while (left >= sizeof(struct ieee80211_info_element)) { | 1080 | while (left >= sizeof(*info_element)) { |
817 | if (sizeof(struct ieee80211_info_element) + info_element->len > | 1081 | if (sizeof(*info_element) + info_element->len > left) { |
818 | left) { | ||
819 | IEEE80211_DEBUG_SCAN | 1082 | IEEE80211_DEBUG_SCAN |
820 | ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", | 1083 | ("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%Zd left=%d.\n", |
821 | info_element->len + | 1084 | info_element->len + sizeof(*info_element), left); |
822 | sizeof(struct ieee80211_info_element), left); | ||
823 | return 1; | 1085 | return 1; |
824 | } | 1086 | } |
825 | 1087 | ||
@@ -847,15 +1109,14 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i | |||
847 | #ifdef CONFIG_IEEE80211_DEBUG | 1109 | #ifdef CONFIG_IEEE80211_DEBUG |
848 | p = rates_str; | 1110 | p = rates_str; |
849 | #endif | 1111 | #endif |
850 | network->rates_len = | 1112 | network->rates_len = min(info_element->len, |
851 | min(info_element->len, MAX_RATES_LENGTH); | 1113 | MAX_RATES_LENGTH); |
852 | for (i = 0; i < network->rates_len; i++) { | 1114 | for (i = 0; i < network->rates_len; i++) { |
853 | network->rates[i] = info_element->data[i]; | 1115 | network->rates[i] = info_element->data[i]; |
854 | #ifdef CONFIG_IEEE80211_DEBUG | 1116 | #ifdef CONFIG_IEEE80211_DEBUG |
855 | p += snprintf(p, | 1117 | p += snprintf(p, sizeof(rates_str) - |
856 | sizeof(rates_str) - (p - | 1118 | (p - rates_str), "%02X ", |
857 | rates_str), | 1119 | network->rates[i]); |
858 | "%02X ", network->rates[i]); | ||
859 | #endif | 1120 | #endif |
860 | if (ieee80211_is_ofdm_rate | 1121 | if (ieee80211_is_ofdm_rate |
861 | (info_element->data[i])) { | 1122 | (info_element->data[i])) { |
@@ -875,15 +1136,14 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i | |||
875 | #ifdef CONFIG_IEEE80211_DEBUG | 1136 | #ifdef CONFIG_IEEE80211_DEBUG |
876 | p = rates_str; | 1137 | p = rates_str; |
877 | #endif | 1138 | #endif |
878 | network->rates_ex_len = | 1139 | network->rates_ex_len = min(info_element->len, |
879 | min(info_element->len, MAX_RATES_EX_LENGTH); | 1140 | MAX_RATES_EX_LENGTH); |
880 | for (i = 0; i < network->rates_ex_len; i++) { | 1141 | for (i = 0; i < network->rates_ex_len; i++) { |
881 | network->rates_ex[i] = info_element->data[i]; | 1142 | network->rates_ex[i] = info_element->data[i]; |
882 | #ifdef CONFIG_IEEE80211_DEBUG | 1143 | #ifdef CONFIG_IEEE80211_DEBUG |
883 | p += snprintf(p, | 1144 | p += snprintf(p, sizeof(rates_str) - |
884 | sizeof(rates_str) - (p - | 1145 | (p - rates_str), "%02X ", |
885 | rates_str), | 1146 | network->rates[i]); |
886 | "%02X ", network->rates[i]); | ||
887 | #endif | 1147 | #endif |
888 | if (ieee80211_is_ofdm_rate | 1148 | if (ieee80211_is_ofdm_rate |
889 | (info_element->data[i])) { | 1149 | (info_element->data[i])) { |
@@ -929,6 +1189,10 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i | |||
929 | case MFIE_TYPE_GENERIC: | 1189 | case MFIE_TYPE_GENERIC: |
930 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", | 1190 | IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", |
931 | info_element->len); | 1191 | info_element->len); |
1192 | if (!ieee80211_parse_qos_info_param_IE(info_element, | ||
1193 | network)) | ||
1194 | break; | ||
1195 | |||
932 | if (info_element->len >= 4 && | 1196 | if (info_element->len >= 4 && |
933 | info_element->data[0] == 0x00 && | 1197 | info_element->data[0] == 0x00 && |
934 | info_element->data[1] == 0x50 && | 1198 | info_element->data[1] == 0x50 && |
@@ -950,14 +1214,18 @@ static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct i | |||
950 | network->rsn_ie_len); | 1214 | network->rsn_ie_len); |
951 | break; | 1215 | break; |
952 | 1216 | ||
1217 | case MFIE_TYPE_QOS_PARAMETER: | ||
1218 | printk(KERN_ERR | ||
1219 | "QoS Error need to parse QOS_PARAMETER IE\n"); | ||
1220 | break; | ||
1221 | |||
953 | default: | 1222 | default: |
954 | IEEE80211_DEBUG_SCAN("unsupported IE %d\n", | 1223 | IEEE80211_DEBUG_SCAN("unsupported IE %d\n", |
955 | info_element->id); | 1224 | info_element->id); |
956 | break; | 1225 | break; |
957 | } | 1226 | } |
958 | 1227 | ||
959 | left -= sizeof(struct ieee80211_info_element) + | 1228 | left -= sizeof(*info_element) + info_element->len; |
960 | info_element->len; | ||
961 | info_element = (struct ieee80211_info_element *) | 1229 | info_element = (struct ieee80211_info_element *) |
962 | &info_element->data[info_element->len]; | 1230 | &info_element->data[info_element->len]; |
963 | } | 1231 | } |
@@ -1004,6 +1272,9 @@ static inline int is_same_network(struct ieee80211_network *src, | |||
1004 | static inline void update_network(struct ieee80211_network *dst, | 1272 | static inline void update_network(struct ieee80211_network *dst, |
1005 | struct ieee80211_network *src) | 1273 | struct ieee80211_network *src) |
1006 | { | 1274 | { |
1275 | int qos_active; | ||
1276 | u8 old_param; | ||
1277 | |||
1007 | memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); | 1278 | memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); |
1008 | dst->capability = src->capability; | 1279 | dst->capability = src->capability; |
1009 | memcpy(dst->rates, src->rates, src->rates_len); | 1280 | memcpy(dst->rates, src->rates, src->rates_len); |
@@ -1026,6 +1297,28 @@ static inline void update_network(struct ieee80211_network *dst, | |||
1026 | dst->rsn_ie_len = src->rsn_ie_len; | 1297 | dst->rsn_ie_len = src->rsn_ie_len; |
1027 | 1298 | ||
1028 | dst->last_scanned = jiffies; | 1299 | dst->last_scanned = jiffies; |
1300 | qos_active = src->qos_data.active; | ||
1301 | old_param = dst->qos_data.old_param_count; | ||
1302 | if (dst->flags & NETWORK_HAS_QOS_MASK) | ||
1303 | memcpy(&dst->qos_data, &src->qos_data, | ||
1304 | sizeof(struct ieee80211_qos_data)); | ||
1305 | else { | ||
1306 | dst->qos_data.supported = src->qos_data.supported; | ||
1307 | dst->qos_data.param_count = src->qos_data.param_count; | ||
1308 | } | ||
1309 | |||
1310 | if (dst->qos_data.supported == 1) { | ||
1311 | if (dst->ssid_len) | ||
1312 | IEEE80211_DEBUG_QOS | ||
1313 | ("QoS the network %s is QoS supported\n", | ||
1314 | dst->ssid); | ||
1315 | else | ||
1316 | IEEE80211_DEBUG_QOS | ||
1317 | ("QoS the network is QoS supported\n"); | ||
1318 | } | ||
1319 | dst->qos_data.active = qos_active; | ||
1320 | dst->qos_data.old_param_count = old_param; | ||
1321 | |||
1029 | /* dst->last_associate is not overwritten */ | 1322 | /* dst->last_associate is not overwritten */ |
1030 | } | 1323 | } |
1031 | 1324 | ||
@@ -1167,6 +1460,9 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, | |||
1167 | IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", | 1460 | IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", |
1168 | WLAN_FC_GET_STYPE(le16_to_cpu | 1461 | WLAN_FC_GET_STYPE(le16_to_cpu |
1169 | (header->frame_ctl))); | 1462 | (header->frame_ctl))); |
1463 | ieee80211_handle_assoc_resp(ieee, | ||
1464 | (struct ieee80211_assoc_response *) | ||
1465 | header, stats); | ||
1170 | break; | 1466 | break; |
1171 | 1467 | ||
1172 | case IEEE80211_STYPE_REASSOC_RESP: | 1468 | case IEEE80211_STYPE_REASSOC_RESP: |
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index e9efdd42ba37..aba72f9880a1 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c | |||
@@ -465,7 +465,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
465 | dev_kfree_skb_any(skb); | 465 | dev_kfree_skb_any(skb); |
466 | 466 | ||
467 | if (txb) { | 467 | if (txb) { |
468 | int ret = (*ieee->hard_start_xmit) (txb, dev); | 468 | int ret = (*ieee->hard_start_xmit) (txb, dev, priority); |
469 | if (ret == 0) { | 469 | if (ret == 0) { |
470 | stats->tx_packets++; | 470 | stats->tx_packets++; |
471 | stats->tx_bytes += txb->payload_size; | 471 | stats->tx_bytes += txb->payload_size; |
@@ -500,6 +500,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, | |||
500 | unsigned long flags; | 500 | unsigned long flags; |
501 | struct net_device_stats *stats = &ieee->stats; | 501 | struct net_device_stats *stats = &ieee->stats; |
502 | struct sk_buff *skb_frag; | 502 | struct sk_buff *skb_frag; |
503 | int priority = -1; | ||
503 | 504 | ||
504 | spin_lock_irqsave(&ieee->lock, flags); | 505 | spin_lock_irqsave(&ieee->lock, flags); |
505 | 506 | ||
@@ -540,7 +541,7 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, | |||
540 | spin_unlock_irqrestore(&ieee->lock, flags); | 541 | spin_unlock_irqrestore(&ieee->lock, flags); |
541 | 542 | ||
542 | if (txb) { | 543 | if (txb) { |
543 | if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) { | 544 | if ((*ieee->hard_start_xmit) (txb, ieee->dev, priority) == 0) { |
544 | stats->tx_packets++; | 545 | stats->tx_packets++; |
545 | stats->tx_bytes += txb->payload_size; | 546 | stats->tx_bytes += txb->payload_size; |
546 | return 0; | 547 | return 0; |