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

[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
...@@ -769,6 +769,27 @@ struct ieee80211_device { ...@@ -769,6 +769,27 @@ struct ieee80211_device {
int (*hard_start_xmit) (struct ieee80211_txb * txb, int (*hard_start_xmit) (struct ieee80211_txb * txb,
struct net_device * dev); struct net_device * dev);
int (*reset_port) (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 /* This must be the last item so that it points to the data
* allocated beyond this structure by alloc_ieee80211 */ * allocated beyond this structure by alloc_ieee80211 */
...@@ -877,6 +898,8 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee); ...@@ -877,6 +898,8 @@ extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
/* ieee80211_tx.c */ /* ieee80211_tx.c */
extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev); extern int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev);
extern void ieee80211_txb_free(struct ieee80211_txb *); 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 */ /* ieee80211_rx.c */
extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
......
...@@ -1029,12 +1029,18 @@ static inline void update_network(struct ieee80211_network *dst, ...@@ -1029,12 +1029,18 @@ static inline void update_network(struct ieee80211_network *dst,
/* dst->last_associate is not overwritten */ /* 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 static inline void ieee80211_process_probe_response(struct ieee80211_device
*ieee, struct *ieee, struct
ieee80211_probe_response ieee80211_probe_response
*beacon, struct ieee80211_rx_stats *beacon, struct ieee80211_rx_stats
*stats) *stats)
{ {
struct net_device *dev = ieee->dev;
struct ieee80211_network network; struct ieee80211_network network;
struct ieee80211_network *target; struct ieee80211_network *target;
struct ieee80211_network *oldest = NULL; struct ieee80211_network *oldest = NULL;
...@@ -1070,11 +1076,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1070,11 +1076,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device
escape_essid(info_element->data, escape_essid(info_element->data,
info_element->len), info_element->len),
MAC_ARG(beacon->header.addr3), MAC_ARG(beacon->header.addr3),
WLAN_FC_GET_STYPE(le16_to_cpu is_beacon(le16_to_cpu
(beacon->header. (beacon->header.
frame_ctl)) == frame_ctl)) ?
IEEE80211_STYPE_PROBE_RESP ? "BEACON" : "PROBE RESPONSE");
"PROBE RESPONSE" : "BEACON");
return; return;
} }
...@@ -1123,11 +1128,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1123,11 +1128,10 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device
escape_essid(network.ssid, escape_essid(network.ssid,
network.ssid_len), network.ssid_len),
MAC_ARG(network.bssid), MAC_ARG(network.bssid),
WLAN_FC_GET_STYPE(le16_to_cpu is_beacon(le16_to_cpu
(beacon->header. (beacon->header.
frame_ctl)) == frame_ctl)) ?
IEEE80211_STYPE_PROBE_RESP ? "BEACON" : "PROBE RESPONSE");
"PROBE RESPONSE" : "BEACON");
#endif #endif
memcpy(target, &network, sizeof(*target)); memcpy(target, &network, sizeof(*target));
list_add_tail(&target->list, &ieee->network_list); list_add_tail(&target->list, &ieee->network_list);
...@@ -1136,15 +1140,22 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1136,15 +1140,22 @@ static inline void ieee80211_process_probe_response(struct ieee80211_device
escape_essid(target->ssid, escape_essid(target->ssid,
target->ssid_len), target->ssid_len),
MAC_ARG(target->bssid), MAC_ARG(target->bssid),
WLAN_FC_GET_STYPE(le16_to_cpu is_beacon(le16_to_cpu
(beacon->header. (beacon->header.
frame_ctl)) == frame_ctl)) ?
IEEE80211_STYPE_PROBE_RESP ? "BEACON" : "PROBE RESPONSE");
"PROBE RESPONSE" : "BEACON");
update_network(target, &network); update_network(target, &network);
} }
spin_unlock_irqrestore(&ieee->lock, flags); 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, void ieee80211_rx_mgt(struct ieee80211_device *ieee,
...@@ -1185,6 +1196,23 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, ...@@ -1185,6 +1196,23 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
ieee80211_probe_response *) ieee80211_probe_response *)
header, stats); header, stats);
break; 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: default:
IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n",
......
...@@ -459,7 +459,71 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -459,7 +459,71 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
stats->tx_errors++; stats->tx_errors++;
return 1; 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); EXPORT_SYMBOL(ieee80211_txb_free);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment