diff options
Diffstat (limited to 'net/mac80211/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 165 |
1 files changed, 155 insertions, 10 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d06c65fa5526..1063a7e57d62 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -411,7 +411,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
411 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | | 411 | BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) | |
412 | BIT(NL80211_STA_FLAG_WME) | | 412 | BIT(NL80211_STA_FLAG_WME) | |
413 | BIT(NL80211_STA_FLAG_MFP) | | 413 | BIT(NL80211_STA_FLAG_MFP) | |
414 | BIT(NL80211_STA_FLAG_AUTHENTICATED); | 414 | BIT(NL80211_STA_FLAG_AUTHENTICATED) | |
415 | BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
415 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) | 416 | if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) |
416 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); | 417 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED); |
417 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) | 418 | if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE)) |
@@ -422,6 +423,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
422 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); | 423 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP); |
423 | if (test_sta_flag(sta, WLAN_STA_AUTH)) | 424 | if (test_sta_flag(sta, WLAN_STA_AUTH)) |
424 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); | 425 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED); |
426 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
427 | sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER); | ||
425 | } | 428 | } |
426 | 429 | ||
427 | 430 | ||
@@ -488,6 +491,31 @@ static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata, | |||
488 | (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); | 491 | (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE); |
489 | } | 492 | } |
490 | 493 | ||
494 | static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, | ||
495 | u8 *resp, size_t resp_len) | ||
496 | { | ||
497 | struct sk_buff *new, *old; | ||
498 | |||
499 | if (!resp || !resp_len) | ||
500 | return -EINVAL; | ||
501 | |||
502 | old = sdata->u.ap.probe_resp; | ||
503 | |||
504 | new = dev_alloc_skb(resp_len); | ||
505 | if (!new) | ||
506 | return -ENOMEM; | ||
507 | |||
508 | memcpy(skb_put(new, resp_len), resp, resp_len); | ||
509 | |||
510 | rcu_assign_pointer(sdata->u.ap.probe_resp, new); | ||
511 | synchronize_rcu(); | ||
512 | |||
513 | if (old) | ||
514 | dev_kfree_skb(old); | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
491 | /* | 519 | /* |
492 | * This handles both adding a beacon and setting new beacon info | 520 | * This handles both adding a beacon and setting new beacon info |
493 | */ | 521 | */ |
@@ -498,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
498 | int new_head_len, new_tail_len; | 526 | int new_head_len, new_tail_len; |
499 | int size; | 527 | int size; |
500 | int err = -EINVAL; | 528 | int err = -EINVAL; |
529 | u32 changed = 0; | ||
501 | 530 | ||
502 | old = rtnl_dereference(sdata->u.ap.beacon); | 531 | old = rtnl_dereference(sdata->u.ap.beacon); |
503 | 532 | ||
@@ -581,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
581 | 610 | ||
582 | kfree(old); | 611 | kfree(old); |
583 | 612 | ||
613 | err = ieee80211_set_probe_resp(sdata, params->probe_resp, | ||
614 | params->probe_resp_len); | ||
615 | if (!err) | ||
616 | changed |= BSS_CHANGED_AP_PROBE_RESP; | ||
617 | |||
584 | ieee80211_config_ap_ssid(sdata, params); | 618 | ieee80211_config_ap_ssid(sdata, params); |
619 | changed |= BSS_CHANGED_BEACON_ENABLED | | ||
620 | BSS_CHANGED_BEACON | | ||
621 | BSS_CHANGED_SSID; | ||
585 | 622 | ||
586 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 623 | ieee80211_bss_info_change_notify(sdata, changed); |
587 | BSS_CHANGED_BEACON | | ||
588 | BSS_CHANGED_SSID); | ||
589 | return 0; | 624 | return 0; |
590 | } | 625 | } |
591 | 626 | ||
@@ -594,6 +629,8 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
594 | { | 629 | { |
595 | struct ieee80211_sub_if_data *sdata; | 630 | struct ieee80211_sub_if_data *sdata; |
596 | struct beacon_data *old; | 631 | struct beacon_data *old; |
632 | struct ieee80211_sub_if_data *vlan; | ||
633 | int ret; | ||
597 | 634 | ||
598 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 635 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
599 | 636 | ||
@@ -601,7 +638,24 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
601 | if (old) | 638 | if (old) |
602 | return -EALREADY; | 639 | return -EALREADY; |
603 | 640 | ||
604 | return ieee80211_config_beacon(sdata, params); | 641 | ret = ieee80211_config_beacon(sdata, params); |
642 | if (ret) | ||
643 | return ret; | ||
644 | |||
645 | /* | ||
646 | * Apply control port protocol, this allows us to | ||
647 | * not encrypt dynamic WEP control frames. | ||
648 | */ | ||
649 | sdata->control_port_protocol = params->crypto.control_port_ethertype; | ||
650 | sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt; | ||
651 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) { | ||
652 | vlan->control_port_protocol = | ||
653 | params->crypto.control_port_ethertype; | ||
654 | vlan->control_port_no_encrypt = | ||
655 | params->crypto.control_port_no_encrypt; | ||
656 | } | ||
657 | |||
658 | return 0; | ||
605 | } | 659 | } |
606 | 660 | ||
607 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | 661 | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, |
@@ -847,7 +901,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
847 | 901 | ||
848 | sta_apply_parameters(local, sta, params); | 902 | sta_apply_parameters(local, sta, params); |
849 | 903 | ||
850 | rate_control_rate_init(sta); | 904 | /* |
905 | * for TDLS, rate control should be initialized only when supported | ||
906 | * rates are known. | ||
907 | */ | ||
908 | if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) | ||
909 | rate_control_rate_init(sta); | ||
851 | 910 | ||
852 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 911 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
853 | sdata->vif.type == NL80211_IFTYPE_AP; | 912 | sdata->vif.type == NL80211_IFTYPE_AP; |
@@ -931,6 +990,9 @@ static int ieee80211_change_station(struct wiphy *wiphy, | |||
931 | 990 | ||
932 | sta_apply_parameters(local, sta, params); | 991 | sta_apply_parameters(local, sta, params); |
933 | 992 | ||
993 | if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates) | ||
994 | rate_control_rate_init(sta); | ||
995 | |||
934 | rcu_read_unlock(); | 996 | rcu_read_unlock(); |
935 | 997 | ||
936 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 998 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
@@ -1394,7 +1456,7 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1394 | (old_oper_type != local->_oper_channel_type)) | 1456 | (old_oper_type != local->_oper_channel_type)) |
1395 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1457 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1396 | 1458 | ||
1397 | if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) && | 1459 | if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR && |
1398 | old_vif_oper_type != sdata->vif.bss_conf.channel_type) | 1460 | old_vif_oper_type != sdata->vif.bss_conf.channel_type) |
1399 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); | 1461 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); |
1400 | 1462 | ||
@@ -1917,7 +1979,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1917 | enum nl80211_channel_type channel_type, | 1979 | enum nl80211_channel_type channel_type, |
1918 | bool channel_type_valid, unsigned int wait, | 1980 | bool channel_type_valid, unsigned int wait, |
1919 | const u8 *buf, size_t len, bool no_cck, | 1981 | const u8 *buf, size_t len, bool no_cck, |
1920 | u64 *cookie) | 1982 | bool dont_wait_for_ack, u64 *cookie) |
1921 | { | 1983 | { |
1922 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1984 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1923 | struct ieee80211_local *local = sdata->local; | 1985 | struct ieee80211_local *local = sdata->local; |
@@ -1925,10 +1987,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, | |||
1925 | struct sta_info *sta; | 1987 | struct sta_info *sta; |
1926 | struct ieee80211_work *wk; | 1988 | struct ieee80211_work *wk; |
1927 | const struct ieee80211_mgmt *mgmt = (void *)buf; | 1989 | const struct ieee80211_mgmt *mgmt = (void *)buf; |
1928 | u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | 1990 | u32 flags; |
1929 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1930 | bool is_offchan = false; | 1991 | bool is_offchan = false; |
1931 | 1992 | ||
1993 | if (dont_wait_for_ack) | ||
1994 | flags = IEEE80211_TX_CTL_NO_ACK; | ||
1995 | else | ||
1996 | flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX | | ||
1997 | IEEE80211_TX_CTL_REQ_TX_STATUS; | ||
1998 | |||
1932 | /* Check that we are on the requested channel for transmission */ | 1999 | /* Check that we are on the requested channel for transmission */ |
1933 | if (chan != local->tmp_channel && | 2000 | if (chan != local->tmp_channel && |
1934 | chan != local->oper_channel) | 2001 | chan != local->oper_channel) |
@@ -2488,6 +2555,82 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, | |||
2488 | return 0; | 2555 | return 0; |
2489 | } | 2556 | } |
2490 | 2557 | ||
2558 | static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, | ||
2559 | const u8 *peer, u64 *cookie) | ||
2560 | { | ||
2561 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2562 | struct ieee80211_local *local = sdata->local; | ||
2563 | struct ieee80211_qos_hdr *nullfunc; | ||
2564 | struct sk_buff *skb; | ||
2565 | int size = sizeof(*nullfunc); | ||
2566 | __le16 fc; | ||
2567 | bool qos; | ||
2568 | struct ieee80211_tx_info *info; | ||
2569 | struct sta_info *sta; | ||
2570 | |||
2571 | rcu_read_lock(); | ||
2572 | sta = sta_info_get(sdata, peer); | ||
2573 | if (sta) { | ||
2574 | qos = test_sta_flag(sta, WLAN_STA_WME); | ||
2575 | rcu_read_unlock(); | ||
2576 | } else { | ||
2577 | rcu_read_unlock(); | ||
2578 | return -ENOLINK; | ||
2579 | } | ||
2580 | |||
2581 | if (qos) { | ||
2582 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
2583 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
2584 | IEEE80211_FCTL_FROMDS); | ||
2585 | } else { | ||
2586 | size -= 2; | ||
2587 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
2588 | IEEE80211_STYPE_NULLFUNC | | ||
2589 | IEEE80211_FCTL_FROMDS); | ||
2590 | } | ||
2591 | |||
2592 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + size); | ||
2593 | if (!skb) | ||
2594 | return -ENOMEM; | ||
2595 | |||
2596 | skb->dev = dev; | ||
2597 | |||
2598 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2599 | |||
2600 | nullfunc = (void *) skb_put(skb, size); | ||
2601 | nullfunc->frame_control = fc; | ||
2602 | nullfunc->duration_id = 0; | ||
2603 | memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN); | ||
2604 | memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN); | ||
2605 | memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN); | ||
2606 | nullfunc->seq_ctrl = 0; | ||
2607 | |||
2608 | info = IEEE80211_SKB_CB(skb); | ||
2609 | |||
2610 | info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS | | ||
2611 | IEEE80211_TX_INTFL_NL80211_FRAME_TX; | ||
2612 | |||
2613 | skb_set_queue_mapping(skb, IEEE80211_AC_VO); | ||
2614 | skb->priority = 7; | ||
2615 | if (qos) | ||
2616 | nullfunc->qos_ctrl = cpu_to_le16(7); | ||
2617 | |||
2618 | local_bh_disable(); | ||
2619 | ieee80211_xmit(sdata, skb); | ||
2620 | local_bh_enable(); | ||
2621 | |||
2622 | *cookie = (unsigned long) skb; | ||
2623 | return 0; | ||
2624 | } | ||
2625 | |||
2626 | static struct ieee80211_channel * | ||
2627 | ieee80211_wiphy_get_channel(struct wiphy *wiphy) | ||
2628 | { | ||
2629 | struct ieee80211_local *local = wiphy_priv(wiphy); | ||
2630 | |||
2631 | return local->oper_channel; | ||
2632 | } | ||
2633 | |||
2491 | struct cfg80211_ops mac80211_config_ops = { | 2634 | struct cfg80211_ops mac80211_config_ops = { |
2492 | .add_virtual_intf = ieee80211_add_iface, | 2635 | .add_virtual_intf = ieee80211_add_iface, |
2493 | .del_virtual_intf = ieee80211_del_iface, | 2636 | .del_virtual_intf = ieee80211_del_iface, |
@@ -2553,4 +2696,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
2553 | .set_rekey_data = ieee80211_set_rekey_data, | 2696 | .set_rekey_data = ieee80211_set_rekey_data, |
2554 | .tdls_oper = ieee80211_tdls_oper, | 2697 | .tdls_oper = ieee80211_tdls_oper, |
2555 | .tdls_mgmt = ieee80211_tdls_mgmt, | 2698 | .tdls_mgmt = ieee80211_tdls_mgmt, |
2699 | .probe_client = ieee80211_probe_client, | ||
2700 | .get_channel = ieee80211_wiphy_get_channel, | ||
2556 | }; | 2701 | }; |