aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2003-07-09 17:46:55 (GMT)
committerJouni Malinen <j@w1.fi>2003-07-09 17:46:55 (GMT)
commit2b5ef382e67670918d7c73ca50ccdec26531426f (patch)
tree20cded89c9aad695bbf71322ff4d2f8ac41333bd
parentca84b4e6dee26711ec63bd30a7a74c9a41fd378a (diff)
downloadhostap-history-2b5ef382e67670918d7c73ca50ccdec26531426f.zip
hostap-history-2b5ef382e67670918d7c73ca50ccdec26531426f.tar.gz
hostap-history-2b5ef382e67670918d7c73ca50ccdec26531426f.tar.bz2
Cleaned up RX handling of frames with too long or negative
data_len. Accept these in monitor mode, but drop in all other modes. Handle negative length properly so that dev_alloc_skb() is used with large enough buffer (system crashes reported in monitor mode).
-rw-r--r--driver/modules/hostap_hw.c55
1 files changed, 36 insertions, 19 deletions
diff --git a/driver/modules/hostap_hw.c b/driver/modules/hostap_hw.c
index 34adb32..05d6a56 100644
--- a/driver/modules/hostap_hw.c
+++ b/driver/modules/hostap_hw.c
@@ -2150,7 +2150,7 @@ static void prism2_rx(local_info_t *local)
{
struct net_device *dev = local->dev;
int res, rx_pending = 0;
- u16 len, alloc_len, rxfid, status, macport;
+ u16 len, hdr_len, rxfid, status, macport;
struct net_device_stats *stats;
struct hfa384x_rx_frame rxdesc;
struct sk_buff *skb = NULL;
@@ -2185,6 +2185,7 @@ static void prism2_rx(local_info_t *local)
}
len = le16_to_cpu(rxdesc.data_len);
+ hdr_len = sizeof(rxdesc);
status = le16_to_cpu(rxdesc.status);
macport = (status >> 8) & 0x07;
@@ -2192,17 +2193,23 @@ static void prism2_rx(local_info_t *local)
* seems to sometimes pass frames (e.g., ctrl::ack) with signed and
* negative value, so allow also values 65522 .. 65534 (-14 .. -2) for
* macport 7 */
- if ((len & 0x8000) &&
- (macport != 7 || ((len < (u16) -14) && len != 0xffff))) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Received frame with invalid length "
- "0x%04x\n", dev->name, len);
- hostap_dump_rx_header(dev->name, &rxdesc);
- goto rx_dropped;
+ if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {
+ if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {
+ if (len >= (u16) -14) {
+ hdr_len -= 65535 - len;
+ hdr_len--;
+ }
+ len = 0;
+ } else {
+ spin_unlock(&local->baplock);
+ printk(KERN_DEBUG "%s: Received frame with invalid "
+ "length 0x%04x\n", dev->name, len);
+ hostap_dump_rx_header(dev->name, &rxdesc);
+ goto rx_dropped;
+ }
}
- alloc_len = len + sizeof(rxdesc);
- skb = dev_alloc_skb(alloc_len);
+ skb = dev_alloc_skb(len + hdr_len);
if (!skb) {
spin_unlock(&local->baplock);
printk(KERN_DEBUG "%s: RX failed to allocate skb\n",
@@ -2210,11 +2217,10 @@ static void prism2_rx(local_info_t *local)
goto rx_dropped;
}
skb->dev = dev;
- memcpy(skb_put(skb, sizeof(rxdesc)), &rxdesc,
- alloc_len < sizeof(rxdesc) ? alloc_len : sizeof(rxdesc));
+ memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len);
#if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER)
- if (!(len & 0x8000) && len >= local->bus_master_threshold_rx) {
+ if (len >= local->bus_master_threshold_rx) {
unsigned long addr;
hfa384x_events_no_bap1(dev);
@@ -2243,7 +2249,7 @@ static void prism2_rx(local_info_t *local)
} else
#endif /* PRISM2_PCI and PRISM2_BUS_MASTER */
{
- if (!(len & 0x8000))
+ if (len > 0)
res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len),
len);
spin_unlock(&local->baplock);
@@ -2279,16 +2285,24 @@ static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
struct hfa384x_rx_frame *rxdesc;
struct net_device *dev = skb->dev;
struct hostap_80211_rx_status stats;
- int hdrlen;
+ int hdrlen, rx_hdrlen;
+ rx_hdrlen = sizeof(*rxdesc);
if (skb->len < sizeof(*rxdesc)) {
- dev_kfree_skb(skb);
- return;
+ /* Allow monitor mode to receive shorter frames */
+ if (local->iw_mode == IW_MODE_MONITOR &&
+ skb->len >= sizeof(*rxdesc) - 30) {
+ rx_hdrlen = skb->len;
+ } else {
+ dev_kfree_skb(skb);
+ return;
+ }
}
rxdesc = (struct hfa384x_rx_frame *) skb->data;
- if (local->frame_dump & PRISM2_DUMP_RX_HDR)
+ if (local->frame_dump & PRISM2_DUMP_RX_HDR &&
+ skb->len >= sizeof(*rxdesc))
hostap_dump_rx_header(dev->name, rxdesc);
if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&
@@ -2309,7 +2323,10 @@ static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
/* Convert Prism2 RX structure into IEEE 802.11 header */
hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control));
- memmove(skb_pull(skb, sizeof(*rxdesc) - hdrlen),
+ if (hdrlen > rx_hdrlen)
+ hdrlen = rx_hdrlen;
+
+ memmove(skb_pull(skb, rx_hdrlen - hdrlen),
&rxdesc->frame_control, hdrlen);
hostap_80211_rx(dev, skb, &stats);