diff options
| author | Luis Carlos Cobo <luisca@cozybit.com> | 2008-02-23 09:17:10 -0500 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:41 -0500 |
| commit | 33b64eb2b1b1759cbdafbe5c59df652f1e7c746e (patch) | |
| tree | 10b314d244e4a44229a6b0da85c3ac76cce2c895 /net | |
| parent | 2e3c8736820bf72a8ad10721c7e31d36d4fa7790 (diff) | |
mac80211: support for mesh interfaces in mac80211 data path
This changes the TX/RX paths in mac80211 to support mesh interfaces.
This code will be cleaned up later again before being enabled.
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
| -rw-r--r-- | net/mac80211/rx.c | 121 | ||||
| -rw-r--r-- | net/mac80211/tx.c | 158 |
2 files changed, 246 insertions, 33 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b7eeae0d3956..cc4a896c617f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -20,6 +20,9 @@ | |||
| 20 | 20 | ||
| 21 | #include "ieee80211_i.h" | 21 | #include "ieee80211_i.h" |
| 22 | #include "ieee80211_led.h" | 22 | #include "ieee80211_led.h" |
| 23 | #ifdef CONFIG_MAC80211_MESH | ||
| 24 | #include "mesh.h" | ||
| 25 | #endif | ||
| 23 | #include "wep.h" | 26 | #include "wep.h" |
| 24 | #include "wpa.h" | 27 | #include "wpa.h" |
| 25 | #include "tkip.h" | 28 | #include "tkip.h" |
| @@ -390,10 +393,60 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) | |||
| 390 | return RX_CONTINUE; | 393 | return RX_CONTINUE; |
| 391 | } | 394 | } |
| 392 | 395 | ||
| 396 | #ifdef CONFIG_MAC80211_MESH | ||
| 397 | #define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) | ||
| 398 | static ieee80211_rx_result | ||
| 399 | ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) | ||
| 400 | { | ||
| 401 | int hdrlen = ieee80211_get_hdrlen(rx->fc); | ||
| 402 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | ||
| 403 | if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { | ||
| 404 | if (!((rx->fc & IEEE80211_FCTL_FROMDS) && | ||
| 405 | (rx->fc & IEEE80211_FCTL_TODS))) | ||
| 406 | return RX_DROP_MONITOR; | ||
| 407 | if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) | ||
| 408 | return RX_DROP_MONITOR; | ||
| 409 | } | ||
| 410 | |||
| 411 | /* If there is not an established peer link and this is not a peer link | ||
| 412 | * establisment frame, beacon or probe, drop the frame. | ||
| 413 | */ | ||
| 414 | |||
| 415 | if (!rx->sta || rx->sta->plink_state != ESTAB) { | ||
| 416 | struct ieee80211_mgmt *mgmt; | ||
| 417 | if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) | ||
| 418 | return RX_DROP_MONITOR; | ||
| 419 | |||
| 420 | switch (rx->fc & IEEE80211_FCTL_STYPE) { | ||
| 421 | case IEEE80211_STYPE_ACTION: | ||
| 422 | mgmt = (struct ieee80211_mgmt *)hdr; | ||
| 423 | if (mgmt->u.action.category != PLINK_CATEGORY) | ||
| 424 | return RX_DROP_MONITOR; | ||
| 425 | /* fall through on else */ | ||
| 426 | case IEEE80211_STYPE_PROBE_REQ: | ||
| 427 | case IEEE80211_STYPE_PROBE_RESP: | ||
| 428 | case IEEE80211_STYPE_BEACON: | ||
| 429 | return RX_CONTINUE; | ||
| 430 | break; | ||
| 431 | default: | ||
| 432 | return RX_DROP_MONITOR; | ||
| 433 | } | ||
| 434 | |||
| 435 | } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && | ||
| 436 | is_broadcast_ether_addr(hdr->addr1) && | ||
| 437 | mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) | ||
| 438 | return RX_DROP_MONITOR; | ||
| 439 | else | ||
| 440 | return RX_CONTINUE; | ||
| 441 | } | ||
| 442 | #endif | ||
| 443 | |||
| 444 | |||
| 393 | static ieee80211_rx_result | 445 | static ieee80211_rx_result |
| 394 | ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | 446 | ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) |
| 395 | { | 447 | { |
| 396 | struct ieee80211_hdr *hdr; | 448 | struct ieee80211_hdr *hdr; |
| 449 | |||
| 397 | hdr = (struct ieee80211_hdr *) rx->skb->data; | 450 | hdr = (struct ieee80211_hdr *) rx->skb->data; |
| 398 | 451 | ||
| 399 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ | 452 | /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ |
| @@ -423,6 +476,12 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) | |||
| 423 | * deauth/disassoc frames when needed. In addition, hostapd is | 476 | * deauth/disassoc frames when needed. In addition, hostapd is |
| 424 | * responsible for filtering on both auth and assoc states. | 477 | * responsible for filtering on both auth and assoc states. |
| 425 | */ | 478 | */ |
| 479 | |||
| 480 | #ifdef CONFIG_MAC80211_MESH | ||
| 481 | if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
| 482 | return ieee80211_rx_mesh_check(rx); | ||
| 483 | #endif | ||
| 484 | |||
| 426 | if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || | 485 | if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || |
| 427 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && | 486 | ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && |
| 428 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && | 487 | (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && |
| @@ -657,6 +716,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) | |||
| 657 | /* Update last_rx only for unicast frames in order to prevent | 716 | /* Update last_rx only for unicast frames in order to prevent |
| 658 | * the Probe Request frames (the only broadcast frames from a | 717 | * the Probe Request frames (the only broadcast frames from a |
| 659 | * STA in infrastructure mode) from keeping a connection alive. | 718 | * STA in infrastructure mode) from keeping a connection alive. |
| 719 | * Mesh beacons will update last_rx when if they are found to | ||
| 720 | * match the current local configuration when processed. | ||
| 660 | */ | 721 | */ |
| 661 | sta->last_rx = jiffies; | 722 | sta->last_rx = jiffies; |
| 662 | } | 723 | } |
| @@ -1050,6 +1111,23 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
| 1050 | 1111 | ||
| 1051 | hdrlen = ieee80211_get_hdrlen(fc); | 1112 | hdrlen = ieee80211_get_hdrlen(fc); |
| 1052 | 1113 | ||
| 1114 | #ifdef CONFIG_MAC80211_MESH | ||
| 1115 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { | ||
| 1116 | int meshhdrlen = ieee80211_get_mesh_hdrlen( | ||
| 1117 | (struct ieee80211s_hdr *) (skb->data + hdrlen)); | ||
| 1118 | /* Copy on cb: | ||
| 1119 | * - mesh header: to be used for mesh forwarding | ||
| 1120 | * decision. It will also be used as mesh header template at | ||
| 1121 | * tx.c:ieee80211_subif_start_xmit() if interface | ||
| 1122 | * type is mesh and skb->pkt_type == PACKET_OTHERHOST | ||
| 1123 | * - ta: to be used if a RERR needs to be sent. | ||
| 1124 | */ | ||
| 1125 | memcpy(skb->cb, skb->data + hdrlen, meshhdrlen); | ||
| 1126 | memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN); | ||
| 1127 | hdrlen += meshhdrlen; | ||
| 1128 | } | ||
| 1129 | #endif | ||
| 1130 | |||
| 1053 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet | 1131 | /* convert IEEE 802.11 header + possible LLC headers into Ethernet |
| 1054 | * header | 1132 | * header |
| 1055 | * IEEE 802.11 address fields: | 1133 | * IEEE 802.11 address fields: |
| @@ -1083,9 +1161,10 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) | |||
| 1083 | memcpy(dst, hdr->addr3, ETH_ALEN); | 1161 | memcpy(dst, hdr->addr3, ETH_ALEN); |
| 1084 | memcpy(src, hdr->addr4, ETH_ALEN); | 1162 | memcpy(src, hdr->addr4, ETH_ALEN); |
| 1085 | 1163 | ||
| 1086 | if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) { | 1164 | if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS && |
| 1087 | if (net_ratelimit()) | 1165 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) { |
| 1088 | printk(KERN_DEBUG "%s: dropped FromDS&ToDS " | 1166 | if (net_ratelimit()) |
| 1167 | printk(KERN_DEBUG "%s: dropped FromDS&ToDS " | ||
| 1089 | "frame (RA=%s TA=%s DA=%s SA=%s)\n", | 1168 | "frame (RA=%s TA=%s DA=%s SA=%s)\n", |
| 1090 | rx->dev->name, | 1169 | rx->dev->name, |
| 1091 | print_mac(mac, hdr->addr1), | 1170 | print_mac(mac, hdr->addr1), |
| @@ -1227,6 +1306,39 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) | |||
| 1227 | } | 1306 | } |
| 1228 | } | 1307 | } |
| 1229 | 1308 | ||
| 1309 | #ifdef CONFIG_MAC80211_MESH | ||
| 1310 | /* Mesh forwarding */ | ||
| 1311 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { | ||
| 1312 | u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl; | ||
| 1313 | (*mesh_ttl)--; | ||
| 1314 | |||
| 1315 | if (is_multicast_ether_addr(skb->data)) { | ||
| 1316 | if (*mesh_ttl > 0) { | ||
| 1317 | xmit_skb = skb_copy(skb, GFP_ATOMIC); | ||
| 1318 | if (!xmit_skb && net_ratelimit()) | ||
| 1319 | printk(KERN_DEBUG "%s: failed to clone " | ||
| 1320 | "multicast frame\n", dev->name); | ||
| 1321 | else | ||
| 1322 | xmit_skb->pkt_type = PACKET_OTHERHOST; | ||
| 1323 | } else | ||
| 1324 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
| 1325 | |||
| 1326 | } else if (skb->pkt_type != PACKET_OTHERHOST && | ||
| 1327 | compare_ether_addr(dev->dev_addr, skb->data) != 0) { | ||
| 1328 | if (*mesh_ttl == 0) { | ||
| 1329 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
| 1330 | dev_kfree_skb(skb); | ||
| 1331 | skb = NULL; | ||
| 1332 | } else { | ||
| 1333 | xmit_skb = skb; | ||
| 1334 | xmit_skb->pkt_type = PACKET_OTHERHOST; | ||
| 1335 | if (!(dev->flags & IFF_PROMISC)) | ||
| 1336 | skb = NULL; | ||
| 1337 | } | ||
| 1338 | } | ||
| 1339 | } | ||
| 1340 | #endif | ||
| 1341 | |||
| 1230 | if (skb) { | 1342 | if (skb) { |
| 1231 | /* deliver to local stack */ | 1343 | /* deliver to local stack */ |
| 1232 | skb->protocol = eth_type_trans(skb, dev); | 1344 | skb->protocol = eth_type_trans(skb, dev); |
| @@ -1444,7 +1556,8 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) | |||
| 1444 | 1556 | ||
| 1445 | sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1557 | sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
| 1446 | if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || | 1558 | if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || |
| 1447 | sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && | 1559 | sdata->vif.type == IEEE80211_IF_TYPE_IBSS || |
| 1560 | sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) && | ||
| 1448 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) | 1561 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) |
| 1449 | ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); | 1562 | ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); |
| 1450 | else | 1563 | else |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1cd58e01f1ee..fc1ffb55ed5c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
| @@ -26,6 +26,9 @@ | |||
| 26 | 26 | ||
| 27 | #include "ieee80211_i.h" | 27 | #include "ieee80211_i.h" |
| 28 | #include "ieee80211_led.h" | 28 | #include "ieee80211_led.h" |
| 29 | #ifdef CONFIG_MAC80211_MESH | ||
| 30 | #include "mesh.h" | ||
| 31 | #endif | ||
| 29 | #include "wep.h" | 32 | #include "wep.h" |
| 30 | #include "wpa.h" | 33 | #include "wpa.h" |
| 31 | #include "wme.h" | 34 | #include "wme.h" |
| @@ -249,6 +252,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) | |||
| 249 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) | 252 | (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) |
| 250 | return TX_DROP; | 253 | return TX_DROP; |
| 251 | 254 | ||
| 255 | if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
| 256 | return TX_CONTINUE; | ||
| 257 | |||
| 252 | if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) | 258 | if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) |
| 253 | return TX_CONTINUE; | 259 | return TX_CONTINUE; |
| 254 | 260 | ||
| @@ -1384,8 +1390,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1384 | struct ieee80211_tx_packet_data *pkt_data; | 1390 | struct ieee80211_tx_packet_data *pkt_data; |
| 1385 | struct ieee80211_sub_if_data *sdata; | 1391 | struct ieee80211_sub_if_data *sdata; |
| 1386 | int ret = 1, head_need; | 1392 | int ret = 1, head_need; |
| 1387 | u16 ethertype, hdrlen, fc; | 1393 | u16 ethertype, hdrlen, meshhdrlen = 0, fc; |
| 1388 | struct ieee80211_hdr hdr; | 1394 | struct ieee80211_hdr hdr; |
| 1395 | struct ieee80211s_hdr mesh_hdr; | ||
| 1389 | const u8 *encaps_data; | 1396 | const u8 *encaps_data; |
| 1390 | int encaps_len, skip_header_bytes; | 1397 | int encaps_len, skip_header_bytes; |
| 1391 | int nh_pos, h_pos; | 1398 | int nh_pos, h_pos; |
| @@ -1427,6 +1434,37 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1427 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | 1434 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); |
| 1428 | hdrlen = 30; | 1435 | hdrlen = 30; |
| 1429 | break; | 1436 | break; |
| 1437 | #ifdef CONFIG_MAC80211_MESH | ||
| 1438 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
| 1439 | fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | ||
| 1440 | /* RA TA DA SA */ | ||
| 1441 | if (is_multicast_ether_addr(skb->data)) | ||
| 1442 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | ||
| 1443 | else if (mesh_nexthop_lookup(hdr.addr1, skb, dev)) | ||
| 1444 | return 0; | ||
| 1445 | memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); | ||
| 1446 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | ||
| 1447 | memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); | ||
| 1448 | if (skb->pkt_type == PACKET_OTHERHOST) { | ||
| 1449 | /* Forwarded frame, keep mesh ttl and seqnum */ | ||
| 1450 | struct ieee80211s_hdr *prev_meshhdr; | ||
| 1451 | prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); | ||
| 1452 | meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); | ||
| 1453 | memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen); | ||
| 1454 | sdata->u.sta.mshstats.fwded_frames++; | ||
| 1455 | } else { | ||
| 1456 | if (!sdata->u.sta.mshcfg.dot11MeshTTL) { | ||
| 1457 | /* Do not send frames with mesh_ttl == 0 */ | ||
| 1458 | sdata->u.sta.mshstats.dropped_frames_ttl++; | ||
| 1459 | ret = 0; | ||
| 1460 | goto fail; | ||
| 1461 | } | ||
| 1462 | meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, | ||
| 1463 | sdata); | ||
| 1464 | } | ||
| 1465 | hdrlen = 30; | ||
| 1466 | break; | ||
| 1467 | #endif | ||
| 1430 | case IEEE80211_IF_TYPE_STA: | 1468 | case IEEE80211_IF_TYPE_STA: |
| 1431 | fc |= IEEE80211_FCTL_TODS; | 1469 | fc |= IEEE80211_FCTL_TODS; |
| 1432 | /* BSSID SA DA */ | 1470 | /* BSSID SA DA */ |
| @@ -1471,8 +1509,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1471 | * EAPOL frames from the local station. | 1509 | * EAPOL frames from the local station. |
| 1472 | */ | 1510 | */ |
| 1473 | if (unlikely(!is_multicast_ether_addr(hdr.addr1) && | 1511 | if (unlikely(!is_multicast_ether_addr(hdr.addr1) && |
| 1474 | !(sta_flags & WLAN_STA_AUTHORIZED) && | 1512 | !(sta_flags & WLAN_STA_AUTHORIZED) && |
| 1475 | !(ethertype == ETH_P_PAE && | 1513 | !(ethertype == ETH_P_PAE && |
| 1476 | compare_ether_addr(dev->dev_addr, | 1514 | compare_ether_addr(dev->dev_addr, |
| 1477 | skb->data + ETH_ALEN) == 0))) { | 1515 | skb->data + ETH_ALEN) == 0))) { |
| 1478 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1516 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| @@ -1525,7 +1563,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1525 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and | 1563 | * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and |
| 1526 | * alloc_skb() (net/core/skbuff.c) | 1564 | * alloc_skb() (net/core/skbuff.c) |
| 1527 | */ | 1565 | */ |
| 1528 | head_need = hdrlen + encaps_len + local->tx_headroom; | 1566 | head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; |
| 1529 | head_need -= skb_headroom(skb); | 1567 | head_need -= skb_headroom(skb); |
| 1530 | 1568 | ||
| 1531 | /* We are going to modify skb data, so make a copy of it if happens to | 1569 | /* We are going to modify skb data, so make a copy of it if happens to |
| @@ -1559,6 +1597,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
| 1559 | h_pos += encaps_len; | 1597 | h_pos += encaps_len; |
| 1560 | } | 1598 | } |
| 1561 | 1599 | ||
| 1600 | if (meshhdrlen > 0) { | ||
| 1601 | memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen); | ||
| 1602 | nh_pos += meshhdrlen; | ||
| 1603 | h_pos += meshhdrlen; | ||
| 1604 | } | ||
| 1605 | |||
| 1562 | if (fc & IEEE80211_STYPE_QOS_DATA) { | 1606 | if (fc & IEEE80211_STYPE_QOS_DATA) { |
| 1563 | __le16 *qos_control; | 1607 | __le16 *qos_control; |
| 1564 | 1608 | ||
| @@ -1734,6 +1778,40 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, | |||
| 1734 | read_unlock_bh(&local->sta_lock); | 1778 | read_unlock_bh(&local->sta_lock); |
| 1735 | } | 1779 | } |
| 1736 | 1780 | ||
| 1781 | #ifdef CONFIG_MAC80211_MESH | ||
| 1782 | static struct sk_buff *ieee80211_mesh_beacon_get(struct net_device *dev) | ||
| 1783 | { | ||
| 1784 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
| 1785 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
| 1786 | struct ieee80211_mgmt *mgmt; | ||
| 1787 | u8 *pos; | ||
| 1788 | |||
| 1789 | if (!skb) | ||
| 1790 | return NULL; | ||
| 1791 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
| 1792 | mgmt = (struct ieee80211_mgmt *) | ||
| 1793 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
| 1794 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
| 1795 | mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, | ||
| 1796 | IEEE80211_STYPE_BEACON); | ||
| 1797 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
| 1798 | memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); | ||
| 1799 | /* BSSID is left zeroed, wildcard value */ | ||
| 1800 | mgmt->u.beacon.beacon_int = | ||
| 1801 | cpu_to_le16(local->hw.conf.beacon_int); | ||
| 1802 | mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ | ||
| 1803 | |||
| 1804 | pos = skb_put(skb, 2); | ||
| 1805 | *pos++ = WLAN_EID_SSID; | ||
| 1806 | *pos++ = 0x0; | ||
| 1807 | |||
| 1808 | mesh_mgmt_ies_add(skb, dev); | ||
| 1809 | |||
| 1810 | return skb; | ||
| 1811 | } | ||
| 1812 | #endif | ||
| 1813 | |||
| 1814 | |||
| 1737 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | 1815 | struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, |
| 1738 | struct ieee80211_vif *vif, | 1816 | struct ieee80211_vif *vif, |
| 1739 | struct ieee80211_tx_control *control) | 1817 | struct ieee80211_tx_control *control) |
| @@ -1746,6 +1824,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 1746 | struct rate_selection rsel; | 1824 | struct rate_selection rsel; |
| 1747 | struct beacon_data *beacon; | 1825 | struct beacon_data *beacon; |
| 1748 | struct ieee80211_supported_band *sband; | 1826 | struct ieee80211_supported_band *sband; |
| 1827 | int *num_beacons; | ||
| 1828 | int err = 0; | ||
| 1749 | 1829 | ||
| 1750 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 1830 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
| 1751 | 1831 | ||
| @@ -1753,11 +1833,51 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 1753 | 1833 | ||
| 1754 | sdata = vif_to_sdata(vif); | 1834 | sdata = vif_to_sdata(vif); |
| 1755 | bdev = sdata->dev; | 1835 | bdev = sdata->dev; |
| 1756 | ap = &sdata->u.ap; | ||
| 1757 | 1836 | ||
| 1758 | beacon = rcu_dereference(ap->beacon); | 1837 | switch (sdata->vif.type) { |
| 1838 | case IEEE80211_IF_TYPE_AP: | ||
| 1839 | ap = &sdata->u.ap; | ||
| 1840 | beacon = rcu_dereference(ap->beacon); | ||
| 1841 | if (!ap || !beacon) { | ||
| 1842 | err = -1; | ||
| 1843 | break; | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | /* headroom, head length, tail length and maximum TIM length */ | ||
| 1847 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + | ||
| 1848 | beacon->tail_len + 256); | ||
| 1849 | if (!skb) | ||
| 1850 | goto out; | ||
| 1851 | |||
| 1852 | skb_reserve(skb, local->tx_headroom); | ||
| 1853 | memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||
| 1854 | beacon->head_len); | ||
| 1759 | 1855 | ||
| 1760 | if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { | 1856 | ieee80211_include_sequence(sdata, |
| 1857 | (struct ieee80211_hdr *)skb->data); | ||
| 1858 | |||
| 1859 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
| 1860 | |||
| 1861 | if (beacon->tail) | ||
| 1862 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, | ||
| 1863 | beacon->tail_len); | ||
| 1864 | |||
| 1865 | num_beacons = &ap->num_beacons; | ||
| 1866 | break; | ||
| 1867 | |||
| 1868 | #ifdef CONFIG_MAC80211_MESH | ||
| 1869 | case IEEE80211_IF_TYPE_MESH_POINT: | ||
| 1870 | skb = ieee80211_mesh_beacon_get(bdev); | ||
| 1871 | num_beacons = &sdata->u.sta.num_beacons; | ||
| 1872 | break; | ||
| 1873 | #endif | ||
| 1874 | |||
| 1875 | default: | ||
| 1876 | err = -1; | ||
| 1877 | break; | ||
| 1878 | } | ||
| 1879 | |||
| 1880 | if (err) { | ||
| 1761 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1881 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
| 1762 | if (net_ratelimit()) | 1882 | if (net_ratelimit()) |
| 1763 | printk(KERN_DEBUG "no beacon data avail for %s\n", | 1883 | printk(KERN_DEBUG "no beacon data avail for %s\n", |
| @@ -1767,24 +1887,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 1767 | goto out; | 1887 | goto out; |
| 1768 | } | 1888 | } |
| 1769 | 1889 | ||
| 1770 | /* headroom, head length, tail length and maximum TIM length */ | ||
| 1771 | skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + | ||
| 1772 | beacon->tail_len + 256); | ||
| 1773 | if (!skb) | ||
| 1774 | goto out; | ||
| 1775 | |||
| 1776 | skb_reserve(skb, local->tx_headroom); | ||
| 1777 | memcpy(skb_put(skb, beacon->head_len), beacon->head, | ||
| 1778 | beacon->head_len); | ||
| 1779 | |||
| 1780 | ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); | ||
| 1781 | |||
| 1782 | ieee80211_beacon_add_tim(local, ap, skb, beacon); | ||
| 1783 | |||
| 1784 | if (beacon->tail) | ||
| 1785 | memcpy(skb_put(skb, beacon->tail_len), beacon->tail, | ||
| 1786 | beacon->tail_len); | ||
| 1787 | |||
| 1788 | if (control) { | 1890 | if (control) { |
| 1789 | rate_control_get_rate(local->mdev, sband, skb, &rsel); | 1891 | rate_control_get_rate(local->mdev, sband, skb, &rsel); |
| 1790 | if (!rsel.rate) { | 1892 | if (!rsel.rate) { |
| @@ -1808,10 +1910,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
| 1808 | control->retry_limit = 1; | 1910 | control->retry_limit = 1; |
| 1809 | control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; | 1911 | control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; |
| 1810 | } | 1912 | } |
| 1811 | 1913 | (*num_beacons)++; | |
| 1812 | ap->num_beacons++; | 1914 | out: |
| 1813 | |||
| 1814 | out: | ||
| 1815 | rcu_read_unlock(); | 1915 | rcu_read_unlock(); |
| 1816 | return skb; | 1916 | return skb; |
| 1817 | } | 1917 | } |
