]> git.ipfire.org Git - people/ms/linux.git/commitdiff
rtlwifi: Fix endian error in extracting packet type
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Sat, 2 Nov 2013 19:28:35 +0000 (14:28 -0500)
committerBen Hutchings <ben@decadent.org.uk>
Fri, 3 Jan 2014 04:33:19 +0000 (04:33 +0000)
commit 0c5d63f0ab6728f05ddefa25aff55e31297f95e6 upstream.

All of the rtlwifi drivers have an error in the routine that tests if
the data is "special". If it is, the subsequant transmission will be
at the lowest rate to enhance reliability. The 16-bit quantity is
big-endian, but was being extracted in native CPU mode. One of the
effects of this bug is to inhibit association under some conditions
as the TX rate is too high.

Based on suggestions by Joe Perches, the entire routine is rewritten.

One of the local headers contained duplicates of some of the ETH_P_XXX
definitions. These are deleted.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
[bwh: Backported to 3.2: adjust context; use rtl_lps_leave()]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/wifi.h

index b4ce93436d2e705a3661e616c3b7111fa5f64641..a917a2273c29c26ea0f581c6c898e4240d1712a7 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <linux/ip.h>
 #include <linux/module.h>
+#include <linux/udp.h>
 #include "wifi.h"
 #include "rc.h"
 #include "base.h"
@@ -956,60 +957,51 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
        if (!ieee80211_is_data(fc))
                return false;
 
+       ip = (const struct iphdr *)(skb->data + mac_hdr_len +
+                                   SNAP_SIZE + PROTOC_TYPE_SIZE);
+       ether_type = be16_to_cpup((__be16 *)
+                                 (skb->data + mac_hdr_len + SNAP_SIZE));
 
-       ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
-                             SNAP_SIZE + PROTOC_TYPE_SIZE);
-       ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
-       /*      ether_type = ntohs(ether_type); */
-
-       if (ETH_P_IP == ether_type) {
-               if (IPPROTO_UDP == ip->protocol) {
-                       struct udphdr *udp = (struct udphdr *)((u8 *) ip +
-                                                              (ip->ihl << 2));
-                       if (((((u8 *) udp)[1] == 68) &&
-                            (((u8 *) udp)[3] == 67)) ||
-                           ((((u8 *) udp)[1] == 67) &&
-                            (((u8 *) udp)[3] == 68))) {
-                               /*
-                                * 68 : UDP BOOTP client
-                                * 67 : UDP BOOTP server
-                                */
-                               RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV),
-                                        DBG_DMESG, ("dhcp %s !!\n",
-                                                    (is_tx) ? "Tx" : "Rx"));
-
-                               if (is_tx) {
-                                       rtl_lps_leave(hw);
-                                       ppsc->last_delaylps_stamp_jiffies =
-                                           jiffies;
-                               }
-
-                               return true;
-                       }
-               }
-       } else if (ETH_P_ARP == ether_type) {
-               if (is_tx) {
-                       rtl_lps_leave(hw);
-                       ppsc->last_delaylps_stamp_jiffies = jiffies;
-               }
+       switch (ether_type) {
+       case ETH_P_IP: {
+               struct udphdr *udp;
+               u16 src;
+               u16 dst;
 
-               return true;
-       } else if (ETH_P_PAE == ether_type) {
-               RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
-                        ("802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"));
+               if (ip->protocol != IPPROTO_UDP)
+                       return false;
+               udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
+               src = be16_to_cpu(udp->source);
+               dst = be16_to_cpu(udp->dest);
 
-               if (is_tx) {
-                       rtl_lps_leave(hw);
-                       ppsc->last_delaylps_stamp_jiffies = jiffies;
-               }
+               /* If this case involves port 68 (UDP BOOTP client) connecting
+                * with port 67 (UDP BOOTP server), then return true so that
+                * the lowest speed is used.
+                */
+               if (!((src == 68 && dst == 67) || (src == 67 && dst == 68)))
+                       return false;
 
-               return true;
-       } else if (ETH_P_IPV6 == ether_type) {
-               /* IPv6 */
-               return true;
+               RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+                        ("dhcp %s !!\n", is_tx ? "Tx" : "Rx"));
+               break;
        }
-
-       return false;
+       case ETH_P_ARP:
+               break;
+       case ETH_P_PAE:
+               RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG,
+                        ("802.1X %s EAPOL pkt!!\n", is_tx ? "Tx" : "Rx"));
+               break;
+       case ETH_P_IPV6:
+               /* TODO: Is this right? */
+               return false;
+       default:
+               return false;
+       }
+       if (is_tx) {
+               rtl_lps_leave(hw);
+               ppsc->last_delaylps_stamp_jiffies = jiffies;
+       }
+       return true;
 }
 
 /*********************************************************
index 82baaa25dc41da3071be624513398bd6acee20d8..5764ef74d2b1fd2800b69d2b26977f2aec98e29c 100644 (file)
 #define RTL_SLOT_TIME_9                                9
 #define RTL_SLOT_TIME_20                       20
 
-/*related with tcp/ip. */
-/*if_ehther.h*/
-#define ETH_P_PAE              0x888E  /*Port Access Entity (IEEE 802.1X) */
-#define ETH_P_IP               0x0800  /*Internet Protocol packet */
-#define ETH_P_ARP              0x0806  /*Address Resolution packet */
+/*related to tcp/ip. */
 #define SNAP_SIZE              6
 #define PROTOC_TYPE_SIZE       2