[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: James Ketrenos <jketreno@linux.intel.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 71d14c7..d1ae282 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -1029,12 +1029,18 @@
 	/* 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 @@
 				     escape_essid(info_element->data,
 						  info_element->len),
 				     MAC_ARG(beacon->header.addr3),
-				     WLAN_FC_GET_STYPE(le16_to_cpu
-						       (beacon->header.
-							frame_ctl)) ==
-				     IEEE80211_STYPE_PROBE_RESP ?
-				     "PROBE RESPONSE" : "BEACON");
+				     is_beacon(le16_to_cpu
+					       (beacon->header.
+						frame_ctl)) ?
+				     "BEACON" : "PROBE RESPONSE");
 		return;
 	}
 
@@ -1123,11 +1128,10 @@
 				     escape_essid(network.ssid,
 						  network.ssid_len),
 				     MAC_ARG(network.bssid),
-				     WLAN_FC_GET_STYPE(le16_to_cpu
-						       (beacon->header.
-							frame_ctl)) ==
-				     IEEE80211_STYPE_PROBE_RESP ?
-				     "PROBE RESPONSE" : "BEACON");
+				     is_beacon(le16_to_cpu
+					       (beacon->header.
+						frame_ctl)) ?
+				     "BEACON" : "PROBE RESPONSE");
 #endif
 		memcpy(target, &network, sizeof(*target));
 		list_add_tail(&target->list, &ieee->network_list);
@@ -1136,15 +1140,22 @@
 				     escape_essid(target->ssid,
 						  target->ssid_len),
 				     MAC_ARG(target->bssid),
-				     WLAN_FC_GET_STYPE(le16_to_cpu
-						       (beacon->header.
-							frame_ctl)) ==
-				     IEEE80211_STYPE_PROBE_RESP ?
-				     "PROBE RESPONSE" : "BEACON");
+				     is_beacon(le16_to_cpu
+					       (beacon->header.
+						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 @@
 						  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",
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c
index cdee41c..f505aa1 100644
--- a/net/ieee80211/ieee80211_tx.c
+++ b/net/ieee80211/ieee80211_tx.c
@@ -459,7 +459,71 @@
 	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);