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 | |
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>
-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 | } |