diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-12-18 19:31:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:59:45 -0500 |
commit | ce3edf6d0b979fa4d5da7204fd8c6f77f2b8622a (patch) | |
tree | 3608f59fa3c437edfe132a603775111a03dce453 /net/mac80211/rx.c | |
parent | 1946b74ce03c4edecabde80d027da00a7eab56ca (diff) |
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: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 133 |
1 files changed, 68 insertions, 65 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index e65da5780cd3..505159f8dffc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -208,7 +208,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | |||
208 | rthdr->it_len = cpu_to_le16(rtap_len); | 208 | rthdr->it_len = cpu_to_le16(rtap_len); |
209 | } | 209 | } |
210 | 210 | ||
211 | skb_set_mac_header(skb, 0); | 211 | skb_reset_mac_header(skb); |
212 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 212 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
213 | skb->pkt_type = PACKET_OTHERHOST; | 213 | skb->pkt_type = PACKET_OTHERHOST; |
214 | skb->protocol = htons(ETH_P_802_2); | 214 | skb->protocol = htons(ETH_P_802_2); |
@@ -405,18 +405,6 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | |||
405 | return TXRX_DROP; | 405 | return TXRX_DROP; |
406 | } | 406 | } |
407 | 407 | ||
408 | if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) | ||
409 | rx->skb->pkt_type = PACKET_OTHERHOST; | ||
410 | else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0) | ||
411 | rx->skb->pkt_type = PACKET_HOST; | ||
412 | else if (is_multicast_ether_addr(hdr->addr1)) { | ||
413 | if (is_broadcast_ether_addr(hdr->addr1)) | ||
414 | rx->skb->pkt_type = PACKET_BROADCAST; | ||
415 | else | ||
416 | rx->skb->pkt_type = PACKET_MULTICAST; | ||
417 | } else | ||
418 | rx->skb->pkt_type = PACKET_OTHERHOST; | ||
419 | |||
420 | /* Drop disallowed frame classes based on STA auth/assoc state; | 408 | /* Drop disallowed frame classes based on STA auth/assoc state; |
421 | * IEEE 802.11, Chap 5.5. | 409 | * IEEE 802.11, Chap 5.5. |
422 | * | 410 | * |
@@ -990,18 +978,10 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) | |||
990 | } | 978 | } |
991 | 979 | ||
992 | static int | 980 | static int |
993 | ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen) | 981 | ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) |
994 | { | 982 | { |
995 | if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb, hdrlen) && | 983 | if (unlikely(rx->sdata->ieee802_1x_pac && |
996 | rx->sdata->type != IEEE80211_IF_TYPE_STA && | 984 | (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)))) { |
997 | (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) | ||
998 | return 0; | ||
999 | |||
1000 | if (unlikely(rx->sdata->ieee802_1x && | ||
1001 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && | ||
1002 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && | ||
1003 | (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) && | ||
1004 | !ieee80211_is_eapol(rx->skb, hdrlen))) { | ||
1005 | #ifdef CONFIG_MAC80211_DEBUG | 985 | #ifdef CONFIG_MAC80211_DEBUG |
1006 | printk(KERN_DEBUG "%s: dropped frame " | 986 | printk(KERN_DEBUG "%s: dropped frame " |
1007 | "(unauthorized port)\n", rx->dev->name); | 987 | "(unauthorized port)\n", rx->dev->name); |
@@ -1013,7 +993,7 @@ ieee80211_drop_802_1x_pae(struct ieee80211_txrx_data *rx, int hdrlen) | |||
1013 | } | 993 | } |
1014 | 994 | ||
1015 | static int | 995 | static int |
1016 | ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen) | 996 | ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) |
1017 | { | 997 | { |
1018 | /* | 998 | /* |
1019 | * Pass through unencrypted frames if the hardware has | 999 | * Pass through unencrypted frames if the hardware has |
@@ -1026,9 +1006,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx, int hdrlen) | |||
1026 | if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && | 1006 | if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) && |
1027 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && | 1007 | (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && |
1028 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && | 1008 | (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC && |
1029 | (rx->key || rx->sdata->drop_unencrypted) && | 1009 | (rx->key || rx->sdata->drop_unencrypted))) { |
1030 | (rx->sdata->eapol == 0 || | ||
1031 | !ieee80211_is_eapol(rx->skb, hdrlen)))) { | ||
1032 | if (net_ratelimit()) | 1010 | if (net_ratelimit()) |
1033 | printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " | 1011 | printk(KERN_DEBUG "%s: RX non-WEP frame, but expected " |
1034 | "encryption\n", rx->dev->name); | 1012 | "encryption\n", rx->dev->name); |
@@ -1156,6 +1134,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
1156 | } else { | 1134 | } else { |
1157 | struct ethhdr *ehdr; | 1135 | struct ethhdr *ehdr; |
1158 | __be16 len; | 1136 | __be16 len; |
1137 | |||
1159 | skb_pull(skb, hdrlen); | 1138 | skb_pull(skb, hdrlen); |
1160 | len = htons(skb->len); | 1139 | len = htons(skb->len); |
1161 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); | 1140 | ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); |
@@ -1166,6 +1145,34 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
1166 | return 0; | 1145 | return 0; |
1167 | } | 1146 | } |
1168 | 1147 | ||
1148 | /* | ||
1149 | * requires that rx->skb is a frame with ethernet header | ||
1150 | */ | ||
1151 | static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx) | ||
1152 | { | ||
1153 | static const u8 pae_group_addr[ETH_ALEN] | ||
1154 | = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; | ||
1155 | struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; | ||
1156 | |||
1157 | /* | ||
1158 | * Allow EAPOL frames to us/the PAE group address regardless | ||
1159 | * of whether the frame was encrypted or not. | ||
1160 | */ | ||
1161 | if (ehdr->h_proto == htons(ETH_P_PAE) && | ||
1162 | (compare_ether_addr(ehdr->h_dest, rx->dev->dev_addr) == 0 || | ||
1163 | compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0)) | ||
1164 | return true; | ||
1165 | |||
1166 | if (ieee80211_802_1x_port_control(rx) || | ||
1167 | ieee80211_drop_unencrypted(rx)) | ||
1168 | return false; | ||
1169 | |||
1170 | return true; | ||
1171 | } | ||
1172 | |||
1173 | /* | ||
1174 | * requires that rx->skb is a frame with ethernet header | ||
1175 | */ | ||
1169 | static void | 1176 | static void |
1170 | ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | 1177 | ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) |
1171 | { | 1178 | { |
@@ -1173,31 +1180,32 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
1173 | struct ieee80211_local *local = rx->local; | 1180 | struct ieee80211_local *local = rx->local; |
1174 | struct sk_buff *skb, *xmit_skb; | 1181 | struct sk_buff *skb, *xmit_skb; |
1175 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1182 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1183 | struct ethhdr *ehdr = (struct ethhdr *) rx->skb->data; | ||
1184 | struct sta_info *dsta; | ||
1176 | 1185 | ||
1177 | skb = rx->skb; | 1186 | skb = rx->skb; |
1178 | xmit_skb = NULL; | 1187 | xmit_skb = NULL; |
1179 | 1188 | ||
1180 | if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP | 1189 | if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP || |
1181 | || sdata->type == IEEE80211_IF_TYPE_VLAN) && | 1190 | sdata->type == IEEE80211_IF_TYPE_VLAN) && |
1182 | (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { | 1191 | (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { |
1183 | if (is_multicast_ether_addr(skb->data)) { | 1192 | if (is_multicast_ether_addr(ehdr->h_dest)) { |
1184 | /* send multicast frames both to higher layers in | 1193 | /* |
1185 | * local net stack and back to the wireless media */ | 1194 | * send multicast frames both to higher layers in |
1195 | * local net stack and back to the wireless medium | ||
1196 | */ | ||
1186 | xmit_skb = skb_copy(skb, GFP_ATOMIC); | 1197 | xmit_skb = skb_copy(skb, GFP_ATOMIC); |
1187 | if (!xmit_skb && net_ratelimit()) | 1198 | if (!xmit_skb && net_ratelimit()) |
1188 | printk(KERN_DEBUG "%s: failed to clone " | 1199 | printk(KERN_DEBUG "%s: failed to clone " |
1189 | "multicast frame\n", dev->name); | 1200 | "multicast frame\n", dev->name); |
1190 | } else { | 1201 | } else { |
1191 | struct sta_info *dsta; | ||
1192 | dsta = sta_info_get(local, skb->data); | 1202 | dsta = sta_info_get(local, skb->data); |
1193 | if (dsta && !dsta->dev) { | 1203 | if (dsta && dsta->dev == dev) { |
1194 | if (net_ratelimit()) | 1204 | /* |
1195 | printk(KERN_DEBUG "Station with null " | 1205 | * The destination station is associated to |
1196 | "dev structure!\n"); | 1206 | * this AP (in this VLAN), so send the frame |
1197 | } else if (dsta && dsta->dev == dev) { | 1207 | * directly to it and do not pass it to local |
1198 | /* Destination station is associated to this | 1208 | * net stack. |
1199 | * AP, so send the frame directly to it and | ||
1200 | * do not pass the frame to local net stack. | ||
1201 | */ | 1209 | */ |
1202 | xmit_skb = skb; | 1210 | xmit_skb = skb; |
1203 | skb = NULL; | 1211 | skb = NULL; |
@@ -1217,8 +1225,8 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
1217 | if (xmit_skb) { | 1225 | if (xmit_skb) { |
1218 | /* send to wireless media */ | 1226 | /* send to wireless media */ |
1219 | xmit_skb->protocol = htons(ETH_P_802_3); | 1227 | xmit_skb->protocol = htons(ETH_P_802_3); |
1220 | skb_set_network_header(xmit_skb, 0); | 1228 | skb_reset_network_header(xmit_skb); |
1221 | skb_set_mac_header(xmit_skb, 0); | 1229 | skb_reset_mac_header(xmit_skb); |
1222 | dev_queue_xmit(xmit_skb); | 1230 | dev_queue_xmit(xmit_skb); |
1223 | } | 1231 | } |
1224 | } | 1232 | } |
@@ -1303,38 +1311,36 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) | |||
1303 | } | 1311 | } |
1304 | } | 1312 | } |
1305 | 1313 | ||
1306 | skb_set_network_header(frame, 0); | 1314 | skb_reset_network_header(frame); |
1307 | frame->dev = dev; | 1315 | frame->dev = dev; |
1308 | frame->priority = skb->priority; | 1316 | frame->priority = skb->priority; |
1309 | rx->skb = frame; | 1317 | rx->skb = frame; |
1310 | 1318 | ||
1311 | if ((ieee80211_drop_802_1x_pae(rx, 0)) || | ||
1312 | (ieee80211_drop_unencrypted(rx, 0))) { | ||
1313 | if (skb == frame) /* last frame */ | ||
1314 | return TXRX_DROP; | ||
1315 | dev_kfree_skb(frame); | ||
1316 | continue; | ||
1317 | } | ||
1318 | |||
1319 | payload = frame->data; | 1319 | payload = frame->data; |
1320 | ethertype = (payload[6] << 8) | payload[7]; | 1320 | ethertype = (payload[6] << 8) | payload[7]; |
1321 | 1321 | ||
1322 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && | 1322 | if (likely((compare_ether_addr(payload, rfc1042_header) == 0 && |
1323 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | 1323 | ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || |
1324 | compare_ether_addr(payload, | 1324 | compare_ether_addr(payload, |
1325 | bridge_tunnel_header) == 0)) { | 1325 | bridge_tunnel_header) == 0)) { |
1326 | /* remove RFC1042 or Bridge-Tunnel | 1326 | /* remove RFC1042 or Bridge-Tunnel |
1327 | * encapsulation and replace EtherType */ | 1327 | * encapsulation and replace EtherType */ |
1328 | skb_pull(frame, 6); | 1328 | skb_pull(frame, 6); |
1329 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | 1329 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); |
1330 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | 1330 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); |
1331 | } else { | 1331 | } else { |
1332 | memcpy(skb_push(frame, sizeof(__be16)), &len, | 1332 | memcpy(skb_push(frame, sizeof(__be16)), |
1333 | sizeof(__be16)); | 1333 | &len, sizeof(__be16)); |
1334 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | 1334 | memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); |
1335 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | 1335 | memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); |
1336 | } | 1336 | } |
1337 | 1337 | ||
1338 | if (!ieee80211_frame_allowed(rx)) { | ||
1339 | if (skb == frame) /* last frame */ | ||
1340 | return TXRX_DROP; | ||
1341 | dev_kfree_skb(frame); | ||
1342 | continue; | ||
1343 | } | ||
1338 | 1344 | ||
1339 | ieee80211_deliver_skb(rx); | 1345 | ieee80211_deliver_skb(rx); |
1340 | } | 1346 | } |
@@ -1347,7 +1353,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) | |||
1347 | { | 1353 | { |
1348 | struct net_device *dev = rx->dev; | 1354 | struct net_device *dev = rx->dev; |
1349 | u16 fc; | 1355 | u16 fc; |
1350 | int err, hdrlen; | 1356 | int err; |
1351 | 1357 | ||
1352 | fc = rx->fc; | 1358 | fc = rx->fc; |
1353 | if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) | 1359 | if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) |
@@ -1356,16 +1362,13 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) | |||
1356 | if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) | 1362 | if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) |
1357 | return TXRX_DROP; | 1363 | return TXRX_DROP; |
1358 | 1364 | ||
1359 | hdrlen = ieee80211_get_hdrlen(fc); | ||
1360 | |||
1361 | if ((ieee80211_drop_802_1x_pae(rx, hdrlen)) || | ||
1362 | (ieee80211_drop_unencrypted(rx, hdrlen))) | ||
1363 | return TXRX_DROP; | ||
1364 | |||
1365 | err = ieee80211_data_to_8023(rx); | 1365 | err = ieee80211_data_to_8023(rx); |
1366 | if (unlikely(err)) | 1366 | if (unlikely(err)) |
1367 | return TXRX_DROP; | 1367 | return TXRX_DROP; |
1368 | 1368 | ||
1369 | if (!ieee80211_frame_allowed(rx)) | ||
1370 | return TXRX_DROP; | ||
1371 | |||
1369 | rx->skb->dev = dev; | 1372 | rx->skb->dev = dev; |
1370 | 1373 | ||
1371 | dev->stats.rx_packets++; | 1374 | dev->stats.rx_packets++; |