Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f2abf44 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jeff Garzik
Browse files

[PATCH] orinoco: always use 802.11 header for rx processing

If the frame has ToDS flag set, mark it by setting skb->pkt_type to
PACKET_OTHERHOST, so that applications unaware of promiscous mode won't get
uplink (STA->AP) packets for STA->STA transmissions relayed by the AP.
Thanks to John Denker and David Gibson for finding the problem and the
solution.

Patch from Pavel Roskin
parent 95dd91fb
Loading
Loading
Loading
Loading
+52 −53
Original line number Diff line number Diff line
@@ -619,7 +619,9 @@ struct hermes_tx_descriptor_802_11 {
	u16 ethertype;
} __attribute__ ((packed));

/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor {
	/* Control */
	u16 status;
	u32 time;
	u8 silence;
@@ -627,6 +629,18 @@ struct hermes_rx_descriptor {
	u8 rate;
	u8 rxflow;
	u32 reserved;

	/* 802.11 header */
	u16 frame_ctl;
	u16 duration_id;
	u8 addr1[ETH_ALEN];
	u8 addr2[ETH_ALEN];
	u8 addr3[ETH_ALEN];
	u16 seq_ctl;
	u8 addr4[ETH_ALEN];

	/* Data length */
	u16 data_len;
} __attribute__ ((packed));

/********************************************************************/
@@ -1110,12 +1124,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
	struct net_device_stats *stats = &priv->stats;
	struct iw_statistics *wstats = &priv->wstats;
	struct sk_buff *skb = NULL;
	u16 rxfid, status;
	int length, data_len, data_off;
	char *p;
	u16 rxfid, status, fc;
	int length;
	struct hermes_rx_descriptor desc;
	struct header_struct hdr;
	struct ethhdr *eh;
	struct ethhdr *hdr;
	int err;

	rxfid = hermes_read_regn(hw, RXFID);
@@ -1140,23 +1152,13 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
			stats->rx_crc_errors++;
			DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name);
		}
		stats->rx_errors++;
		goto drop;
	}

	/* For now we ignore the 802.11 header completely, assuming
           that the card's firmware has handled anything vital */

	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr),
			       rxfid, HERMES_802_3_OFFSET);
	if (err) {
		printk(KERN_ERR "%s: error %d reading frame header. "
		       "Frame dropped.\n", dev->name, err);
		stats->rx_errors++;
		goto drop;
	}

	length = ntohs(hdr.len);
	length = le16_to_cpu(desc.data_len);
	fc = le16_to_cpu(desc.frame_ctl);

	/* Sanity checks */
	if (length < 3) { /* No for even an 802.2 LLC header */
@@ -1186,57 +1188,51 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
		goto drop;
	}

	skb_reserve(skb, 2); /* This way the IP header is aligned */
	/* We'll prepend the header, so reserve space for it.  The worst
	   case is no decapsulation, when 802.3 header is prepended and
	   nothing is removed.  2 is for aligning the IP header.  */
	skb_reserve(skb, ETH_HLEN + 2);

	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
			       ALIGN(length, 2), rxfid,
			       HERMES_802_2_OFFSET);
	if (err) {
		printk(KERN_ERR "%s: error %d reading frame. "
		       "Frame dropped.\n", dev->name, err);
		stats->rx_errors++;
		goto drop;
	}

	/* Handle decapsulation
	 * In most cases, the firmware tell us about SNAP frames.
	 * For some reason, the SNAP frames sent by LinkSys APs
	 * are not properly recognised by most firmwares.
	 * So, check ourselves */
	if (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
	if (length >= ENCAPS_OVERHEAD &&
	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
	    is_ethersnap(&hdr)) {
	     is_ethersnap(skb->data))) {
		/* These indicate a SNAP within 802.2 LLC within
		   802.11 frame which we'll need to de-encapsulate to
		   the original EthernetII frame. */

		if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
			stats->rx_length_errors++;
			goto drop;
		}

		/* Remove SNAP header, reconstruct EthernetII frame */
		data_len = length - ENCAPS_OVERHEAD;
		data_off = HERMES_802_3_OFFSET + sizeof(hdr);

		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);

		memcpy(eh, &hdr, 2 * ETH_ALEN);
		eh->h_proto = hdr.ethertype;
		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
	} else {
		/* All other cases indicate a genuine 802.3 frame.  No
		   decapsulation needed.  We just throw the whole
		   thing in, and hope the protocol layer can deal with
		   it as 802.3 */
		data_len = length;
		data_off = HERMES_802_3_OFFSET;
		/* FIXME: we re-read from the card data we already read here */
	}

	p = skb_put(skb, data_len);
	err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2),
			       rxfid, data_off);
	if (err) {
		printk(KERN_ERR "%s: error %d reading frame. "
		       "Frame dropped.\n", dev->name, err);
		stats->rx_errors++;
		goto drop;
		/* 802.3 frame - prepend 802.3 header as is */
		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
		hdr->h_proto = htons(length);
	}
	memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
	if (fc & IEEE80211_FCTL_FROMDS)
		memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
	else
		memcpy(hdr->h_source, desc.addr2, ETH_ALEN);

	dev->last_rx = jiffies;
	skb->dev = dev;
	skb->protocol = eth_type_trans(skb, dev);
	skb->ip_summed = CHECKSUM_NONE;
	if (fc & IEEE80211_FCTL_TODS)
		skb->pkt_type = PACKET_OTHERHOST;
	
	/* Process the wireless stats if needed */
	orinoco_stat_gather(dev, skb, &desc);
@@ -1457,6 +1453,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
		u16 newstatus;
		int connected;

		if (priv->iw_mode == IW_MODE_MONITOR)
			break;

		if (len != sizeof(linkstatus)) {
			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
			       dev->name, len);