Commit ce3edf6d authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller

mac80211: clean up eapol frame handling/port control

This cleans up the eapol frame handling and some related code in the
receive and transmit paths. After this patch
 * EAPOL frames addressed to us or the EAPOL group address are
   always accepted regardless of whether they are encrypted or not
 * other frames from a station are dropped if PAE is enabled and
   the station is not authorized
 * unencrypted frames (except the EAPOL frames above) are dropped if
   drop_unencrypted is enabled
 * some superfluous code that eth_type_trans handles anyway is gone
 * port control is done for transmitted packets
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1946b74c
...@@ -91,8 +91,7 @@ static const struct file_operations name##_ops = { \ ...@@ -91,8 +91,7 @@ static const struct file_operations name##_ops = { \
/* common attributes */ /* common attributes */
IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(channel_use, channel_use, DEC);
IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
IEEE80211_IF_FILE(eapol, eapol, DEC); IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC);
IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
/* STA/IBSS attributes */ /* STA/IBSS attributes */
IEEE80211_IF_FILE(state, u.sta.state, DEC); IEEE80211_IF_FILE(state, u.sta.state, DEC);
...@@ -170,8 +169,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) ...@@ -170,8 +169,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(channel_use, sta); DEBUGFS_ADD(channel_use, sta);
DEBUGFS_ADD(drop_unencrypted, sta); DEBUGFS_ADD(drop_unencrypted, sta);
DEBUGFS_ADD(eapol, sta); DEBUGFS_ADD(ieee802_1x_pac, sta);
DEBUGFS_ADD(ieee8021_x, sta);
DEBUGFS_ADD(state, sta); DEBUGFS_ADD(state, sta);
DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(bssid, sta);
DEBUGFS_ADD(prev_bssid, sta); DEBUGFS_ADD(prev_bssid, sta);
...@@ -192,8 +190,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) ...@@ -192,8 +190,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(channel_use, ap); DEBUGFS_ADD(channel_use, ap);
DEBUGFS_ADD(drop_unencrypted, ap); DEBUGFS_ADD(drop_unencrypted, ap);
DEBUGFS_ADD(eapol, ap); DEBUGFS_ADD(ieee802_1x_pac, ap);
DEBUGFS_ADD(ieee8021_x, ap);
DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(num_sta_ps, ap);
DEBUGFS_ADD(dtim_period, ap); DEBUGFS_ADD(dtim_period, ap);
DEBUGFS_ADD(dtim_count, ap); DEBUGFS_ADD(dtim_count, ap);
...@@ -209,8 +206,7 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) ...@@ -209,8 +206,7 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(channel_use, wds); DEBUGFS_ADD(channel_use, wds);
DEBUGFS_ADD(drop_unencrypted, wds); DEBUGFS_ADD(drop_unencrypted, wds);
DEBUGFS_ADD(eapol, wds); DEBUGFS_ADD(ieee802_1x_pac, wds);
DEBUGFS_ADD(ieee8021_x, wds);
DEBUGFS_ADD(peer, wds); DEBUGFS_ADD(peer, wds);
} }
...@@ -218,8 +214,7 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) ...@@ -218,8 +214,7 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_ADD(channel_use, vlan); DEBUGFS_ADD(channel_use, vlan);
DEBUGFS_ADD(drop_unencrypted, vlan); DEBUGFS_ADD(drop_unencrypted, vlan);
DEBUGFS_ADD(eapol, vlan); DEBUGFS_ADD(ieee802_1x_pac, vlan);
DEBUGFS_ADD(ieee8021_x, vlan);
} }
static void add_monitor_files(struct ieee80211_sub_if_data *sdata) static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
...@@ -263,8 +258,7 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) ...@@ -263,8 +258,7 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(channel_use, sta); DEBUGFS_DEL(channel_use, sta);
DEBUGFS_DEL(drop_unencrypted, sta); DEBUGFS_DEL(drop_unencrypted, sta);
DEBUGFS_DEL(eapol, sta); DEBUGFS_DEL(ieee802_1x_pac, sta);
DEBUGFS_DEL(ieee8021_x, sta);
DEBUGFS_DEL(state, sta); DEBUGFS_DEL(state, sta);
DEBUGFS_DEL(bssid, sta); DEBUGFS_DEL(bssid, sta);
DEBUGFS_DEL(prev_bssid, sta); DEBUGFS_DEL(prev_bssid, sta);
...@@ -285,8 +279,7 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) ...@@ -285,8 +279,7 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(channel_use, ap); DEBUGFS_DEL(channel_use, ap);
DEBUGFS_DEL(drop_unencrypted, ap); DEBUGFS_DEL(drop_unencrypted, ap);
DEBUGFS_DEL(eapol, ap); DEBUGFS_DEL(ieee802_1x_pac, ap);
DEBUGFS_DEL(ieee8021_x, ap);
DEBUGFS_DEL(num_sta_ps, ap); DEBUGFS_DEL(num_sta_ps, ap);
DEBUGFS_DEL(dtim_period, ap); DEBUGFS_DEL(dtim_period, ap);
DEBUGFS_DEL(dtim_count, ap); DEBUGFS_DEL(dtim_count, ap);
...@@ -302,8 +295,7 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata) ...@@ -302,8 +295,7 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(channel_use, wds); DEBUGFS_DEL(channel_use, wds);
DEBUGFS_DEL(drop_unencrypted, wds); DEBUGFS_DEL(drop_unencrypted, wds);
DEBUGFS_DEL(eapol, wds); DEBUGFS_DEL(ieee802_1x_pac, wds);
DEBUGFS_DEL(ieee8021_x, wds);
DEBUGFS_DEL(peer, wds); DEBUGFS_DEL(peer, wds);
} }
...@@ -311,8 +303,7 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) ...@@ -311,8 +303,7 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
{ {
DEBUGFS_DEL(channel_use, vlan); DEBUGFS_DEL(channel_use, vlan);
DEBUGFS_DEL(drop_unencrypted, vlan); DEBUGFS_DEL(drop_unencrypted, vlan);
DEBUGFS_DEL(eapol, vlan); DEBUGFS_DEL(ieee802_1x_pac, vlan);
DEBUGFS_DEL(ieee8021_x, vlan);
} }
static void del_monitor_files(struct ieee80211_sub_if_data *sdata) static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
......
...@@ -306,11 +306,11 @@ struct ieee80211_sub_if_data { ...@@ -306,11 +306,11 @@ struct ieee80211_sub_if_data {
unsigned int flags; unsigned int flags;
int drop_unencrypted; int drop_unencrypted;
int eapol; /* 0 = process EAPOL frames as normal data frames, /*
* 1 = send EAPOL frames through wlan#ap to hostapd * IEEE 802.1X Port access control in effect,
* (default) */ * drop packets to/from unauthorized port
int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized */
* port */ int ieee802_1x_pac;
u16 sequence; u16 sequence;
...@@ -339,8 +339,7 @@ struct ieee80211_sub_if_data { ...@@ -339,8 +339,7 @@ struct ieee80211_sub_if_data {
struct { struct {
struct dentry *channel_use; struct dentry *channel_use;
struct dentry *drop_unencrypted; struct dentry *drop_unencrypted;
struct dentry *eapol; struct dentry *ieee802_1x_pac;
struct dentry *ieee8021_x;
struct dentry *state; struct dentry *state;
struct dentry *bssid; struct dentry *bssid;
struct dentry *prev_bssid; struct dentry *prev_bssid;
...@@ -359,8 +358,7 @@ struct ieee80211_sub_if_data { ...@@ -359,8 +358,7 @@ struct ieee80211_sub_if_data {
struct { struct {
struct dentry *channel_use; struct dentry *channel_use;
struct dentry *drop_unencrypted; struct dentry *drop_unencrypted;
struct dentry *eapol; struct dentry *ieee802_1x_pac;
struct dentry *ieee8021_x;
struct dentry *num_sta_ps; struct dentry *num_sta_ps;
struct dentry *dtim_period; struct dentry *dtim_period;
struct dentry *dtim_count; struct dentry *dtim_count;
...@@ -374,15 +372,13 @@ struct ieee80211_sub_if_data { ...@@ -374,15 +372,13 @@ struct ieee80211_sub_if_data {
struct { struct {
struct dentry *channel_use; struct dentry *channel_use;
struct dentry *drop_unencrypted; struct dentry *drop_unencrypted;
struct dentry *eapol; struct dentry *ieee802_1x_pac;
struct dentry *ieee8021_x;
struct dentry *peer; struct dentry *peer;
} wds; } wds;
struct { struct {
struct dentry *channel_use; struct dentry *channel_use;
struct dentry *drop_unencrypted; struct dentry *drop_unencrypted;
struct dentry *eapol; struct dentry *ieee802_1x_pac;
struct dentry *ieee8021_x;
} vlan; } vlan;
struct { struct {
struct dentry *mode; struct dentry *mode;
......
...@@ -22,7 +22,6 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) ...@@ -22,7 +22,6 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
/* Default values for sub-interface parameters */ /* Default values for sub-interface parameters */
sdata->drop_unencrypted = 0; sdata->drop_unencrypted = 0;
sdata->eapol = 1;
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list); skb_queue_head_init(&sdata->fragments[i].skb_list);
......
...@@ -208,7 +208,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, ...@@ -208,7 +208,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
rthdr->it_len = cpu_to_le16(rtap_len); rthdr->it_len = cpu_to_le16(rtap_len);
} }
skb_set_mac_header(skb, 0); skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->pkt_type = PACKET_OTHERHOST; skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_802_2); skb->protocol = htons(ETH_P_802_2);
...@@ -405,18 +405,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) ...@@ -405,18 +405,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
return TXRX_DROP; return TXRX_DROP;
} }
if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
rx->skb->pkt_type = PACKET_OTHERHOST;
else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
rx->skb->pkt_type = PACKET_HOST;
else if (is_multicast_ether_addr(hdr->addr1)) {
if (is_broadcast_ether_addr(hdr->addr1))
rx->skb->pkt_type = PACKET_BROADCAST;
else
rx->skb->pkt_type = PACKET_MULTICAST;
} else
rx->skb->pkt_type = PACKET_OTHERHOST;
/* Drop disallowed frame classes based on STA auth/assoc state; /* Drop disallowed frame classes based on STA auth/assoc state;
* IEEE 802.11, Chap 5.5. * IEEE 802.11, Chap 5.5.
* *
...@@ -990,18 +978,10 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) ...@@ -990,18 +978,10 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
} }
static int static int
ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen) ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
{ {
if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb, hdrlen) && if (unlikely(rx->sdata->ieee802_1x_pac &&
rx->sdata->type != IEEE80211_IF_TYPE_STA && (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)))) {
(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
return 0;
if (unlikely(rx->sdata->ieee802_1x &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
!ieee80211_is_eapol(rx->skb, hdrlen))) {
#ifdef CONFIG_MAC80211_DEBUG #ifdef CONFIG_MAC80211_DEBUG
printk(KERN_DEBUG "%s: dropped frame " printk(KERN_DEBUG "%s: dropped frame "
"(unauthorized port)\n", rx->dev->name); "(unauthorized port)\n", rx->dev->name);
...@@ -1013,7 +993,7 @@ ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen) ...@@ -1013,7 +993,7 @@ ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen)
} }
static int static int
ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen) ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
{ {
/* /*
* Pass through unencrypted frames if the hardware has * Pass through unencrypted frames if the hardware has
...@@ -1026,9 +1006,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen) ...@@ -1026,9 +1006,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen)
if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
(rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
(rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
(rx->key || rx->sdata->drop_unencrypted) && (rx->key || rx->sdata->drop_unencrypted))) {
(rx->sdata->eapol == 0 ||
!ieee80211_is_eapol(rx->skb, hdrlen)))) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
"encryption\n", rx->dev->name); "encryption\n", rx->dev->name);
...@@ -1156,6 +1134,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) ...@@ -1156,6 +1134,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
} else { } else {
struct ethhdr *ehdr; struct ethhdr *ehdr;
__be16 len; __be16 len;
skb_pull(skb, hdrlen); skb_pull(skb, hdrlen);
len = htons(skb->len); len = htons(skb->len);
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
...@@ -1166,6 +1145,34 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) ...@@ -1166,6 +1145,34 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
return 0; return 0;
} }
/*
* requires that rx->skb is a frame with ethernet header
*/
static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
{
static const u8 pae_group_addr[ETH_ALEN]
= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
/*
* Allow EAPOL frames to us/the PAE group address regardless
* of whether the frame was encrypted or not.
*/
if (ehdr->h_proto == htons(ETH_P_PAE) &&
(compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 ||
compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
return true;
if (ieee80211_802_1x_port_control(rx) ||
ieee80211_drop_unencrypted(rx))
return false;
return true;
}
/*
* requires that rx->skb is a frame with ethernet header
*/
static void static void
ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
{ {
...@@ -1173,31 +1180,32 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) ...@@ -1173,31 +1180,32 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
struct ieee80211_local *local = rx->local; struct ieee80211_local *local = rx->local;
struct sk_buff *skb, *xmit_skb; struct sk_buff *skb, *xmit_skb;
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data;
struct sta_info *dsta;
skb = rx->skb; skb = rx->skb;
xmit_skb = NULL; xmit_skb = NULL;
if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP ||
|| sdata->type == IEEE80211_IF_TYPE_VLAN) && sdata->type == IEEE80211_IF_TYPE_VLAN) &&
(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
if (is_multicast_ether_addr(skb->data)) { if (is_multicast_ether_addr(ehdr->h_dest)) {
/* send multicast frames both to higher layers in /*
* local net stack and back to the wireless media */ * send multicast frames both to higher layers in
* local net stack and back to the wireless medium
*/
xmit_skb = skb_copy(skb, GFP_ATOMIC); xmit_skb = skb_copy(skb, GFP_ATOMIC);
if (!xmit_skb && net_ratelimit()) if (!xmit_skb && net_ratelimit())
printk(KERN_DEBUG "%s: failed to clone " printk(KERN_DEBUG "%s: failed to clone "
"multicast frame\n", dev->name); "multicast frame\n", dev->name);
} else { } else {
struct sta_info *dsta;
dsta = sta_info_get(local, skb->data); dsta = sta_info_get(local, skb->data);
if (dsta && !dsta->dev) { if (dsta && dsta->dev == dev) {
if (net_ratelimit()) /*
printk(KERN_DEBUG "Station with null " * The destination station is associated to
"dev structure!\n"); * this AP (in this VLAN), so send the frame
} else if (dsta && dsta->dev == dev) { * directly to it and do not pass it to local
/* Destination station is associated to this * net stack.
* AP, so send the frame directly to it and
* do not pass the frame to local net stack.
*/ */
xmit_skb = skb; xmit_skb = skb;
skb = NULL; skb = NULL;
...@@ -1217,8 +1225,8 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) ...@@ -1217,8 +1225,8 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
if (xmit_skb) { if (xmit_skb) {
/* send to wireless media */ /* send to wireless media */
xmit_skb->protocol = htons(ETH_P_802_3); xmit_skb->protocol = htons(ETH_P_802_3);
skb_set_network_header(xmit_skb, 0); skb_reset_network_header(xmit_skb);
skb_set_mac_header(xmit_skb, 0); skb_reset_mac_header(xmit_skb);
dev_queue_xmit(xmit_skb); dev_queue_xmit(xmit_skb);
} }
} }
...@@ -1303,38 +1311,36 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) ...@@ -1303,38 +1311,36 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
} }
} }
skb_set_network_header(frame, 0); skb_reset_network_header(frame);
frame->dev = dev; frame->dev = dev;
frame->priority = skb->priority; frame->priority = skb->priority;
rx->skb = frame; rx->skb = frame;
if ((ieee80211_drop_802_1x_pae(rx, 0)) ||
(ieee80211_drop_unencrypted(rx, 0))) {
if (skb == frame) /* last frame */
return TXRX_DROP;
dev_kfree_skb(frame);
continue;
}
payload = frame->data; payload = frame->data;
ethertype = (payload[6] << 8) | payload[7]; ethertype = (payload[6] << 8) | payload[7];
if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
compare_ether_addr(payload, compare_ether_addr(payload,
bridge_tunnel_header) == 0)) { bridge_tunnel_header) == 0)) {
/* remove RFC1042 or Bridge-Tunnel /* remove RFC1042 or Bridge-Tunnel
* encapsulation and replace EtherType */ * encapsulation and replace EtherType */
skb_pull(frame, 6); skb_pull(frame, 6);
memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
} else { } else {
memcpy(skb_push(frame, sizeof(__be16)), &len, memcpy(skb_push(frame, sizeof(__be16)),
sizeof(__be16)); &len, sizeof(__be16));
memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
} }
if (!ieee80211_frame_allowed(rx)) {
if (skb == frame) /* last frame */
return TXRX_DROP;
dev_kfree_skb(frame);
continue;
}
ieee80211_deliver_skb(rx); ieee80211_deliver_skb(rx);
} }
...@@ -1347,7 +1353,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) ...@@ -1347,7 +1353,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
{ {
struct net_device *dev = rx->dev; struct net_device *dev = rx->dev;
u16 fc; u16 fc;
int err, hdrlen; int err;
fc = rx->fc; fc = rx->fc;
if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
...@@ -1356,16 +1362,13 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) ...@@ -1356,16 +1362,13 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
return TXRX_DROP; return TXRX_DROP;
hdrlen = ieee80211_get_hdrlen(fc);
if ((ieee80211_drop_802_1x_pae(rx, hdrlen)) ||
(ieee80211_drop_unencrypted(rx, hdrlen)))
return TXRX_DROP;
err = ieee80211_data_to_8023(rx); err = ieee80211_data_to_8023(rx);
if (unlikely(err)) if (unlikely(err))
return TXRX_DROP; return TXRX_DROP;
if (!ieee80211_frame_allowed(rx))
return TXRX_DROP;
rx->skb->dev = dev; rx->skb->dev = dev;
dev->stats.rx_packets++; dev->stats.rx_packets++;
......
...@@ -261,18 +261,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) ...@@ -261,18 +261,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
return TXRX_CONTINUE; return TXRX_CONTINUE;
} }
if (unlikely(/* !injected && */ tx->sdata->ieee802_1x &&
!(sta_flags & WLAN_STA_AUTHORIZED))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
DECLARE_MAC_BUF(mac);
printk(KERN_DEBUG "%s: dropped frame to %s"
" (unauthorized port)\n", tx->dev->name,
print_mac(mac, hdr->addr1));
#endif
I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);
return TXRX_DROP;
}
return TXRX_CONTINUE; return TXRX_CONTINUE;
} }
...@@ -449,8 +437,7 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) ...@@ -449,8 +437,7 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
else if ((key = rcu_dereference(tx->sdata->default_key))) else if ((key = rcu_dereference(tx->sdata->default_key)))
tx->key = key; tx->key = key;
else if (tx->sdata->drop_unencrypted && else if (tx->sdata->drop_unencrypted &&
!(tx->sdata->eapol && !ieee80211_is_eapol(tx->skb, ieee80211_get_hdrlen(fc))) {
ieee80211_is_eapol(tx->skb, ieee80211_get_hdrlen(fc)))) {
I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
return TXRX_DROP; return TXRX_DROP;
} else { } else {
...@@ -1346,6 +1333,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1346,6 +1333,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
int encaps_len, skip_header_bytes; int encaps_len, skip_header_bytes;
int nh_pos, h_pos; int nh_pos, h_pos;
struct sta_info *sta; struct sta_info *sta;
u32 sta_flags = 0;
sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(skb->len < ETH_HLEN)) { if (unlikely(skb->len < ETH_HLEN)) {
...@@ -1361,7 +1349,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1361,7 +1349,6 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
/* convert Ethernet header to proper 802.11 header (based on /* convert Ethernet header to proper 802.11 header (based on
* operation mode) */ * operation mode) */
ethertype = (skb->data[12] << 8) | skb->data[13]; ethertype = (skb->data[12] << 8) | skb->data[13];
/* TODO: handling for 802.1x authorized/unauthorized port */
fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
switch (sdata->type) { switch (sdata->type) {
...@@ -1403,16 +1390,42 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, ...@@ -1403,16 +1390,42 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
goto fail; goto fail;
} }
/* receiver is QoS enabled, use a QoS type frame */
sta = sta_info_get(local, hdr.addr1); sta = sta_info_get(local, hdr.addr1);
if (sta) { if (sta) {
if (sta->flags & WLAN_STA_WME) { sta_flags = sta->flags;
fc |= IEEE80211_STYPE_QOS_DATA;
hdrlen += 2;
}
sta_info_put(sta); sta_info_put(sta);
} }
/* receiver is QoS enabled, use a QoS type frame */
if (sta_flags & WLAN_STA_WME) {
fc |= IEEE80211_STYPE_QOS_DATA;
hdrlen += 2;
}
/*
* If port access control is enabled, drop frames to unauthorised
* stations unless they are EAPOL frames from the local station.
*/
if (unlikely(sdata->ieee802_1x_pac &&
!(sta_flags & WLAN_STA_AUTHORIZED) &&
!(ethertype == ETH_P_PAE &&
compare_ether_addr(dev->dev_addr,
skb->data + ETH_ALEN) == 0))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
DECLARE_MAC_BUF(mac);
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame to %s"
" (unauthorized port)\n", dev->name,
print_mac(mac, hdr.addr1));
#endif
I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
ret = 0;
goto fail;
}
hdr.frame_control = cpu_to_le16(fc); hdr.frame_control = cpu_to_le16(fc);
hdr.duration_id = 0; hdr.duration_id = 0;
hdr.seq_ctrl = 0; hdr.seq_ctrl = 0;
......
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