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

Commit 3f552bbf authored by James Ketrenos's avatar James Ketrenos Committed by Jeff Garzik
Browse files

[PATCH] ieee82011: Added ieee80211_tx_frame to convert generic 802.11 data frames, and callbacks



tree 40adc78b623ae70d56074934ec6334eb4f0ae6a5
parent db43d847bcebaa3df6414e26d0008eb21690e8cf
author James Ketrenos <jketreno@linux.intel.com> 1124445938 -0500
committer James Ketrenos <jketreno@linux.intel.com> 1127313102 -0500

Added ieee80211_tx_frame to convert generic 802.11 data frames into
txbs for transmission.

Added several purpose specific callbacks (handle_assoc, handle_auth,
etc.) which the driver can register with for being notified on
reception of variouf frame elements.

Signed-off-by: default avatarJames Ketrenos <jketreno@linux.intel.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 3cdd00c5
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -769,6 +769,27 @@ struct ieee80211_device {
	int (*hard_start_xmit) (struct ieee80211_txb * txb,
				struct net_device * dev);
	int (*reset_port) (struct net_device * dev);
	int (*is_queue_full) (struct net_device * dev, int pri);

	/* Typical STA methods */
	int (*handle_auth) (struct net_device * dev,
			    struct ieee80211_auth * auth);
	int (*handle_disassoc) (struct net_device * dev,
				struct ieee80211_disassoc * assoc);
	int (*handle_beacon) (struct net_device * dev,
			      struct ieee80211_beacon * beacon,
			      struct ieee80211_network * network);
	int (*handle_probe_response) (struct net_device * dev,
				      struct ieee80211_probe_response * resp,
				      struct ieee80211_network * network);
	int (*handle_assoc_response) (struct net_device * dev,
				      struct ieee80211_assoc_response * resp,
				      struct ieee80211_network * network);

	/* Typical AP methods */
	int (*handle_assoc_request) (struct net_device * dev);
	int (*handle_reassoc_request) (struct net_device * dev,
				       struct ieee80211_reassoc_request * req);

	/* This must be the last item so that it points to the data
	 * allocated beyond this structure by alloc_ieee80211 */
@@ -877,6 +898,8 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
/* ieee80211_tx.c */
extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *);
extern int ieee80211_tx_frame(struct ieee80211_device *ieee,
			      struct ieee80211_hdr *frame, int len);

/* ieee80211_rx.c */
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+43 −15
Original line number Diff line number Diff line
@@ -1029,12 +1029,18 @@ static inline void update_network(struct ieee80211_network *dst,
	/* dst->last_associate is not overwritten */
}

static inline int is_beacon(int fc)
{
	return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
}

static inline void ieee80211_process_probe_response(struct ieee80211_device
						    *ieee, struct
						    ieee80211_probe_response
						    *beacon, struct ieee80211_rx_stats
						    *stats)
{
	struct net_device *dev = ieee->dev;
	struct ieee80211_network network;
	struct ieee80211_network *target;
	struct ieee80211_network *oldest = NULL;
@@ -1070,11 +1076,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device
				     escape_essid(info_element->data,
						  info_element->len),
				     MAC_ARG(beacon->header.addr3),
				     WLAN_FC_GET_STYPE(le16_to_cpu
				     is_beacon(le16_to_cpu
					       (beacon->header.
							frame_ctl)) ==
				     IEEE80211_STYPE_PROBE_RESP ?
				     "PROBE RESPONSE" : "BEACON");
						frame_ctl)) ?
				     "BEACON" : "PROBE RESPONSE");
		return;
	}

@@ -1123,11 +1128,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device
				     escape_essid(network.ssid,
						  network.ssid_len),
				     MAC_ARG(network.bssid),
				     WLAN_FC_GET_STYPE(le16_to_cpu
				     is_beacon(le16_to_cpu
					       (beacon->header.
							frame_ctl)) ==
				     IEEE80211_STYPE_PROBE_RESP ?
				     "PROBE RESPONSE" : "BEACON");
						frame_ctl)) ?
				     "BEACON" : "PROBE RESPONSE");
#endif
		memcpy(target, &network, sizeof(*target));
		list_add_tail(&target->list, &ieee->network_list);
@@ -1136,15 +1140,22 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device
				     escape_essid(target->ssid,
						  target->ssid_len),
				     MAC_ARG(target->bssid),
				     WLAN_FC_GET_STYPE(le16_to_cpu
				     is_beacon(le16_to_cpu
					       (beacon->header.
							frame_ctl)) ==
				     IEEE80211_STYPE_PROBE_RESP ?
				     "PROBE RESPONSE" : "BEACON");
						frame_ctl)) ?
				     "BEACON" : "PROBE RESPONSE");
		update_network(target, &network);
	}

	spin_unlock_irqrestore(&ieee->lock, flags);

	if (is_beacon(le16_to_cpu(beacon->header.frame_ctl))) {
		if (ieee->handle_beacon != NULL)
			ieee->handle_beacon(dev, beacon, &network);
	} else {
		if (ieee->handle_probe_response != NULL)
			ieee->handle_probe_response(dev, beacon, &network);
	}
}

void ieee80211_rx_mgt(struct ieee80211_device *ieee,
@@ -1185,6 +1196,23 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
						  ieee80211_probe_response *)
						 header, stats);
		break;
	case IEEE80211_STYPE_AUTH:

		IEEE80211_DEBUG_MGMT("recieved auth (%d)\n",
				     WLAN_FC_GET_STYPE(le16_to_cpu
						       (header->frame_ctl)));

		if (ieee->handle_auth != NULL)
			ieee->handle_auth(ieee->dev,
					  (struct ieee80211_auth *)header);
		break;

	case IEEE80211_STYPE_DISASSOC:
		if (ieee->handle_disassoc != NULL)
			ieee->handle_disassoc(ieee->dev,
					      (struct ieee80211_disassoc *)
					      header);
		break;

	default:
		IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
+64 −0
Original line number Diff line number Diff line
@@ -459,7 +459,71 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
	netif_stop_queue(dev);
	stats->tx_errors++;
	return 1;
}

/* Incoming 802.11 strucure is converted to a TXB
 * a block of 802.11 fragment packets (stored as skbs) */
int ieee80211_tx_frame(struct ieee80211_device *ieee,
		       struct ieee80211_hdr *frame, int len)
{
	struct ieee80211_txb *txb = NULL;
	unsigned long flags;
	struct net_device_stats *stats = &ieee->stats;
	struct sk_buff *skb_frag;

	spin_lock_irqsave(&ieee->lock, flags);

	/* If there is no driver handler to take the TXB, dont' bother
	 * creating it... */
	if (!ieee->hard_start_xmit) {
		printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
		goto success;
	}

	if (unlikely(len < 24)) {
		printk(KERN_WARNING "%s: skb too small (%d).\n",
		       ieee->dev->name, len);
		goto success;
	}

	/* When we allocate the TXB we allocate enough space for the reserve
	 * and full fragment bytes (bytes_per_frag doesn't include prefix,
	 * postfix, header, FCS, etc.) */
	txb = ieee80211_alloc_txb(1, len, GFP_ATOMIC);
	if (unlikely(!txb)) {
		printk(KERN_WARNING "%s: Could not allocate TXB\n",
		       ieee->dev->name);
		goto failed;
	}
	txb->encrypted = 0;
	txb->payload_size = len;

	skb_frag = txb->fragments[0];

	memcpy(skb_put(skb_frag, len), frame, len);

	if (ieee->config &
	    (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS))
		skb_put(skb_frag, 4);

      success:
	spin_unlock_irqrestore(&ieee->lock, flags);

	if (txb) {
		if ((*ieee->hard_start_xmit) (txb, ieee->dev) == 0) {
			stats->tx_packets++;
			stats->tx_bytes += txb->payload_size;
			return 0;
		}
		ieee80211_txb_free(txb);
	}
	return 0;

      failed:
	spin_unlock_irqrestore(&ieee->lock, flags);
	stats->tx_errors++;
	return 1;
}

EXPORT_SYMBOL(ieee80211_tx_frame);
EXPORT_SYMBOL(ieee80211_txb_free);