diff options
Diffstat (limited to 'net/mac80211/iface.c')
| -rw-r--r-- | net/mac80211/iface.c | 417 |
1 files changed, 353 insertions, 64 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 32abae3ce32a..ebbe264e2b0b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
| 11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
| 12 | */ | 12 | */ |
| 13 | #include <linux/slab.h> | ||
| 13 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 14 | #include <linux/if_arp.h> | 15 | #include <linux/if_arp.h> |
| 15 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
| @@ -62,6 +63,23 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | |||
| 62 | return 0; | 63 | return 0; |
| 63 | } | 64 | } |
| 64 | 65 | ||
| 66 | static int ieee80211_change_mac(struct net_device *dev, void *addr) | ||
| 67 | { | ||
| 68 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 69 | struct sockaddr *sa = addr; | ||
| 70 | int ret; | ||
| 71 | |||
| 72 | if (ieee80211_sdata_running(sdata)) | ||
| 73 | return -EBUSY; | ||
| 74 | |||
| 75 | ret = eth_mac_addr(dev, sa); | ||
| 76 | |||
| 77 | if (ret == 0) | ||
| 78 | memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN); | ||
| 79 | |||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | |||
| 65 | static inline int identical_mac_addr_allowed(int type1, int type2) | 83 | static inline int identical_mac_addr_allowed(int type1, int type2) |
| 66 | { | 84 | { |
| 67 | return type1 == NL80211_IFTYPE_MONITOR || | 85 | return type1 == NL80211_IFTYPE_MONITOR || |
| @@ -82,7 +100,6 @@ static int ieee80211_open(struct net_device *dev) | |||
| 82 | struct ieee80211_sub_if_data *nsdata; | 100 | struct ieee80211_sub_if_data *nsdata; |
| 83 | struct ieee80211_local *local = sdata->local; | 101 | struct ieee80211_local *local = sdata->local; |
| 84 | struct sta_info *sta; | 102 | struct sta_info *sta; |
| 85 | struct ieee80211_if_init_conf conf; | ||
| 86 | u32 changed = 0; | 103 | u32 changed = 0; |
| 87 | int res; | 104 | int res; |
| 88 | u32 hw_reconf_flags = 0; | 105 | u32 hw_reconf_flags = 0; |
| @@ -97,7 +114,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 97 | list_for_each_entry(nsdata, &local->interfaces, list) { | 114 | list_for_each_entry(nsdata, &local->interfaces, list) { |
| 98 | struct net_device *ndev = nsdata->dev; | 115 | struct net_device *ndev = nsdata->dev; |
| 99 | 116 | ||
| 100 | if (ndev != dev && netif_running(ndev)) { | 117 | if (ndev != dev && ieee80211_sdata_running(nsdata)) { |
| 101 | /* | 118 | /* |
| 102 | * Allow only a single IBSS interface to be up at any | 119 | * Allow only a single IBSS interface to be up at any |
| 103 | * time. This is restricted because beacon distribution | 120 | * time. This is restricted because beacon distribution |
| @@ -183,7 +200,7 @@ static int ieee80211_open(struct net_device *dev) | |||
| 183 | struct net_device *ndev = nsdata->dev; | 200 | struct net_device *ndev = nsdata->dev; |
| 184 | 201 | ||
| 185 | /* | 202 | /* |
| 186 | * No need to check netif_running since we do not allow | 203 | * No need to check running since we do not allow |
| 187 | * it to start up with this invalid address. | 204 | * it to start up with this invalid address. |
| 188 | */ | 205 | */ |
| 189 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | 206 | if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { |
| @@ -232,12 +249,11 @@ static int ieee80211_open(struct net_device *dev) | |||
| 232 | local->fif_other_bss++; | 249 | local->fif_other_bss++; |
| 233 | 250 | ||
| 234 | ieee80211_configure_filter(local); | 251 | ieee80211_configure_filter(local); |
| 252 | |||
| 253 | netif_carrier_on(dev); | ||
| 235 | break; | 254 | break; |
| 236 | default: | 255 | default: |
| 237 | conf.vif = &sdata->vif; | 256 | res = drv_add_interface(local, &sdata->vif); |
| 238 | conf.type = sdata->vif.type; | ||
| 239 | conf.mac_addr = dev->dev_addr; | ||
| 240 | res = drv_add_interface(local, &conf); | ||
| 241 | if (res) | 257 | if (res) |
| 242 | goto err_stop; | 258 | goto err_stop; |
| 243 | 259 | ||
| @@ -254,7 +270,6 @@ static int ieee80211_open(struct net_device *dev) | |||
| 254 | 270 | ||
| 255 | changed |= ieee80211_reset_erp_info(sdata); | 271 | changed |= ieee80211_reset_erp_info(sdata); |
| 256 | ieee80211_bss_info_change_notify(sdata, changed); | 272 | ieee80211_bss_info_change_notify(sdata, changed); |
| 257 | ieee80211_enable_keys(sdata); | ||
| 258 | 273 | ||
| 259 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 274 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
| 260 | netif_carrier_off(dev); | 275 | netif_carrier_off(dev); |
| @@ -307,20 +322,11 @@ static int ieee80211_open(struct net_device *dev) | |||
| 307 | 322 | ||
| 308 | ieee80211_recalc_ps(local, -1); | 323 | ieee80211_recalc_ps(local, -1); |
| 309 | 324 | ||
| 310 | /* | ||
| 311 | * ieee80211_sta_work is disabled while network interface | ||
| 312 | * is down. Therefore, some configuration changes may not | ||
| 313 | * yet be effective. Trigger execution of ieee80211_sta_work | ||
| 314 | * to fix this. | ||
| 315 | */ | ||
| 316 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
| 317 | ieee80211_queue_work(&local->hw, &sdata->u.mgd.work); | ||
| 318 | |||
| 319 | netif_tx_start_all_queues(dev); | 325 | netif_tx_start_all_queues(dev); |
| 320 | 326 | ||
| 321 | return 0; | 327 | return 0; |
| 322 | err_del_interface: | 328 | err_del_interface: |
| 323 | drv_remove_interface(local, &conf); | 329 | drv_remove_interface(local, &sdata->vif); |
| 324 | err_stop: | 330 | err_stop: |
| 325 | if (!local->open_count) | 331 | if (!local->open_count) |
| 326 | drv_stop(local); | 332 | drv_stop(local); |
| @@ -335,8 +341,6 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 335 | { | 341 | { |
| 336 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 342 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
| 337 | struct ieee80211_local *local = sdata->local; | 343 | struct ieee80211_local *local = sdata->local; |
| 338 | struct ieee80211_if_init_conf conf; | ||
| 339 | struct sta_info *sta; | ||
| 340 | unsigned long flags; | 344 | unsigned long flags; |
| 341 | struct sk_buff *skb, *tmp; | 345 | struct sk_buff *skb, *tmp; |
| 342 | u32 hw_reconf_flags = 0; | 346 | u32 hw_reconf_flags = 0; |
| @@ -348,16 +352,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 348 | netif_tx_stop_all_queues(dev); | 352 | netif_tx_stop_all_queues(dev); |
| 349 | 353 | ||
| 350 | /* | 354 | /* |
| 351 | * Now delete all active aggregation sessions. | 355 | * Purge work for this interface. |
| 352 | */ | 356 | */ |
| 353 | rcu_read_lock(); | 357 | ieee80211_work_purge(sdata); |
| 354 | |||
| 355 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
| 356 | if (sta->sdata == sdata) | ||
| 357 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
| 358 | } | ||
| 359 | |||
| 360 | rcu_read_unlock(); | ||
| 361 | 358 | ||
| 362 | /* | 359 | /* |
| 363 | * Remove all stations associated with this interface. | 360 | * Remove all stations associated with this interface. |
| @@ -395,8 +392,7 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 395 | 392 | ||
| 396 | netif_addr_lock_bh(dev); | 393 | netif_addr_lock_bh(dev); |
| 397 | spin_lock_bh(&local->filter_lock); | 394 | spin_lock_bh(&local->filter_lock); |
| 398 | __dev_addr_unsync(&local->mc_list, &local->mc_count, | 395 | __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len); |
| 399 | &dev->mc_list, &dev->mc_count); | ||
| 400 | spin_unlock_bh(&local->filter_lock); | 396 | spin_unlock_bh(&local->filter_lock); |
| 401 | netif_addr_unlock_bh(dev); | 397 | netif_addr_unlock_bh(dev); |
| 402 | 398 | ||
| @@ -466,27 +462,14 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 466 | * whether the interface is running, which, at this point, | 462 | * whether the interface is running, which, at this point, |
| 467 | * it no longer is. | 463 | * it no longer is. |
| 468 | */ | 464 | */ |
| 469 | cancel_work_sync(&sdata->u.mgd.work); | ||
| 470 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 465 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
| 471 | cancel_work_sync(&sdata->u.mgd.monitor_work); | 466 | cancel_work_sync(&sdata->u.mgd.monitor_work); |
| 472 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | 467 | cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work); |
| 473 | 468 | ||
| 474 | /* | ||
| 475 | * When we get here, the interface is marked down. | ||
| 476 | * Call synchronize_rcu() to wait for the RX path | ||
| 477 | * should it be using the interface and enqueuing | ||
| 478 | * frames at this very time on another CPU. | ||
| 479 | */ | ||
| 480 | synchronize_rcu(); | ||
| 481 | skb_queue_purge(&sdata->u.mgd.skb_queue); | ||
| 482 | /* fall through */ | 469 | /* fall through */ |
| 483 | case NL80211_IFTYPE_ADHOC: | 470 | case NL80211_IFTYPE_ADHOC: |
| 484 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 471 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
| 485 | del_timer_sync(&sdata->u.ibss.timer); | 472 | del_timer_sync(&sdata->u.ibss.timer); |
| 486 | cancel_work_sync(&sdata->u.ibss.work); | ||
| 487 | synchronize_rcu(); | ||
| 488 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
| 489 | } | ||
| 490 | /* fall through */ | 473 | /* fall through */ |
| 491 | case NL80211_IFTYPE_MESH_POINT: | 474 | case NL80211_IFTYPE_MESH_POINT: |
| 492 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 475 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
| @@ -501,6 +484,16 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 501 | } | 484 | } |
| 502 | /* fall through */ | 485 | /* fall through */ |
| 503 | default: | 486 | default: |
| 487 | flush_work(&sdata->work); | ||
| 488 | /* | ||
| 489 | * When we get here, the interface is marked down. | ||
| 490 | * Call synchronize_rcu() to wait for the RX path | ||
| 491 | * should it be using the interface and enqueuing | ||
| 492 | * frames at this very time on another CPU. | ||
| 493 | */ | ||
| 494 | synchronize_rcu(); | ||
| 495 | skb_queue_purge(&sdata->skb_queue); | ||
| 496 | |||
| 504 | if (local->scan_sdata == sdata) | 497 | if (local->scan_sdata == sdata) |
| 505 | ieee80211_scan_cancel(local); | 498 | ieee80211_scan_cancel(local); |
| 506 | 499 | ||
| @@ -514,12 +507,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
| 514 | BSS_CHANGED_BEACON_ENABLED); | 507 | BSS_CHANGED_BEACON_ENABLED); |
| 515 | } | 508 | } |
| 516 | 509 | ||
| 517 | conf.vif = &sdata->vif; | 510 | /* free all remaining keys, there shouldn't be any */ |
| 518 | conf.type = sdata->vif.type; | 511 | ieee80211_free_keys(sdata); |
| 519 | conf.mac_addr = dev->dev_addr; | 512 | drv_remove_interface(local, &sdata->vif); |
| 520 | /* disable all keys for as long as this netdev is down */ | ||
| 521 | ieee80211_disable_keys(sdata); | ||
| 522 | drv_remove_interface(local, &conf); | ||
| 523 | } | 513 | } |
| 524 | 514 | ||
| 525 | sdata->bss = NULL; | 515 | sdata->bss = NULL; |
| @@ -582,8 +572,7 @@ static void ieee80211_set_multicast_list(struct net_device *dev) | |||
| 582 | sdata->flags ^= IEEE80211_SDATA_PROMISC; | 572 | sdata->flags ^= IEEE80211_SDATA_PROMISC; |
| 583 | } | 573 | } |
| 584 | spin_lock_bh(&local->filter_lock); | 574 | spin_lock_bh(&local->filter_lock); |
| 585 | __dev_addr_sync(&local->mc_list, &local->mc_count, | 575 | __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len); |
| 586 | &dev->mc_list, &dev->mc_count); | ||
| 587 | spin_unlock_bh(&local->filter_lock); | 576 | spin_unlock_bh(&local->filter_lock); |
| 588 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); | 577 | ieee80211_queue_work(&local->hw, &local->reconfig_filter); |
| 589 | } | 578 | } |
| @@ -659,7 +648,7 @@ static const struct net_device_ops ieee80211_dataif_ops = { | |||
| 659 | .ndo_start_xmit = ieee80211_subif_start_xmit, | 648 | .ndo_start_xmit = ieee80211_subif_start_xmit, |
| 660 | .ndo_set_multicast_list = ieee80211_set_multicast_list, | 649 | .ndo_set_multicast_list = ieee80211_set_multicast_list, |
| 661 | .ndo_change_mtu = ieee80211_change_mtu, | 650 | .ndo_change_mtu = ieee80211_change_mtu, |
| 662 | .ndo_set_mac_address = eth_mac_addr, | 651 | .ndo_set_mac_address = ieee80211_change_mac, |
| 663 | .ndo_select_queue = ieee80211_netdev_select_queue, | 652 | .ndo_select_queue = ieee80211_netdev_select_queue, |
| 664 | }; | 653 | }; |
| 665 | 654 | ||
| @@ -681,10 +670,14 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, | |||
| 681 | 670 | ||
| 682 | hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); | 671 | hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); |
| 683 | 672 | ||
| 684 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | 673 | if (!ieee80211_is_data(hdr->frame_control)) { |
| 685 | skb->priority = 7; | 674 | skb->priority = 7; |
| 686 | return ieee802_1d_to_ac[skb->priority]; | 675 | return ieee802_1d_to_ac[skb->priority]; |
| 687 | } | 676 | } |
| 677 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | ||
| 678 | skb->priority = 0; | ||
| 679 | return ieee802_1d_to_ac[skb->priority]; | ||
| 680 | } | ||
| 688 | 681 | ||
| 689 | p = ieee80211_get_qos_ctl(hdr); | 682 | p = ieee80211_get_qos_ctl(hdr); |
| 690 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 683 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
| @@ -710,6 +703,136 @@ static void ieee80211_if_setup(struct net_device *dev) | |||
| 710 | dev->destructor = free_netdev; | 703 | dev->destructor = free_netdev; |
| 711 | } | 704 | } |
| 712 | 705 | ||
| 706 | static void ieee80211_iface_work(struct work_struct *work) | ||
| 707 | { | ||
| 708 | struct ieee80211_sub_if_data *sdata = | ||
| 709 | container_of(work, struct ieee80211_sub_if_data, work); | ||
| 710 | struct ieee80211_local *local = sdata->local; | ||
| 711 | struct sk_buff *skb; | ||
| 712 | struct sta_info *sta; | ||
| 713 | struct ieee80211_ra_tid *ra_tid; | ||
| 714 | |||
| 715 | if (!ieee80211_sdata_running(sdata)) | ||
| 716 | return; | ||
| 717 | |||
| 718 | if (local->scanning) | ||
| 719 | return; | ||
| 720 | |||
| 721 | /* | ||
| 722 | * ieee80211_queue_work() should have picked up most cases, | ||
| 723 | * here we'll pick the rest. | ||
| 724 | */ | ||
| 725 | if (WARN(local->suspended, | ||
| 726 | "interface work scheduled while going to suspend\n")) | ||
| 727 | return; | ||
| 728 | |||
| 729 | /* first process frames */ | ||
| 730 | while ((skb = skb_dequeue(&sdata->skb_queue))) { | ||
| 731 | struct ieee80211_mgmt *mgmt = (void *)skb->data; | ||
| 732 | |||
| 733 | if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) { | ||
| 734 | ra_tid = (void *)&skb->cb; | ||
| 735 | ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra, | ||
| 736 | ra_tid->tid); | ||
| 737 | } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_STOP) { | ||
| 738 | ra_tid = (void *)&skb->cb; | ||
| 739 | ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra, | ||
| 740 | ra_tid->tid); | ||
| 741 | } else if (ieee80211_is_action(mgmt->frame_control) && | ||
| 742 | mgmt->u.action.category == WLAN_CATEGORY_BACK) { | ||
| 743 | int len = skb->len; | ||
| 744 | |||
| 745 | mutex_lock(&local->sta_mtx); | ||
| 746 | sta = sta_info_get_bss(sdata, mgmt->sa); | ||
| 747 | if (sta) { | ||
| 748 | switch (mgmt->u.action.u.addba_req.action_code) { | ||
| 749 | case WLAN_ACTION_ADDBA_REQ: | ||
| 750 | ieee80211_process_addba_request( | ||
| 751 | local, sta, mgmt, len); | ||
| 752 | break; | ||
| 753 | case WLAN_ACTION_ADDBA_RESP: | ||
| 754 | ieee80211_process_addba_resp(local, sta, | ||
| 755 | mgmt, len); | ||
| 756 | break; | ||
| 757 | case WLAN_ACTION_DELBA: | ||
| 758 | ieee80211_process_delba(sdata, sta, | ||
| 759 | mgmt, len); | ||
| 760 | break; | ||
| 761 | default: | ||
| 762 | WARN_ON(1); | ||
| 763 | break; | ||
| 764 | } | ||
| 765 | } | ||
| 766 | mutex_unlock(&local->sta_mtx); | ||
| 767 | } else if (ieee80211_is_data_qos(mgmt->frame_control)) { | ||
| 768 | struct ieee80211_hdr *hdr = (void *)mgmt; | ||
| 769 | /* | ||
| 770 | * So the frame isn't mgmt, but frame_control | ||
| 771 | * is at the right place anyway, of course, so | ||
| 772 | * the if statement is correct. | ||
| 773 | * | ||
| 774 | * Warn if we have other data frame types here, | ||
| 775 | * they must not get here. | ||
| 776 | */ | ||
| 777 | WARN_ON(hdr->frame_control & | ||
| 778 | cpu_to_le16(IEEE80211_STYPE_NULLFUNC)); | ||
| 779 | WARN_ON(!(hdr->seq_ctrl & | ||
| 780 | cpu_to_le16(IEEE80211_SCTL_FRAG))); | ||
| 781 | /* | ||
| 782 | * This was a fragment of a frame, received while | ||
| 783 | * a block-ack session was active. That cannot be | ||
| 784 | * right, so terminate the session. | ||
| 785 | */ | ||
| 786 | mutex_lock(&local->sta_mtx); | ||
| 787 | sta = sta_info_get_bss(sdata, mgmt->sa); | ||
| 788 | if (sta) { | ||
| 789 | u16 tid = *ieee80211_get_qos_ctl(hdr) & | ||
| 790 | IEEE80211_QOS_CTL_TID_MASK; | ||
| 791 | |||
| 792 | __ieee80211_stop_rx_ba_session( | ||
| 793 | sta, tid, WLAN_BACK_RECIPIENT, | ||
| 794 | WLAN_REASON_QSTA_REQUIRE_SETUP); | ||
| 795 | } | ||
| 796 | mutex_unlock(&local->sta_mtx); | ||
| 797 | } else switch (sdata->vif.type) { | ||
| 798 | case NL80211_IFTYPE_STATION: | ||
| 799 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | ||
| 800 | break; | ||
| 801 | case NL80211_IFTYPE_ADHOC: | ||
| 802 | ieee80211_ibss_rx_queued_mgmt(sdata, skb); | ||
| 803 | break; | ||
| 804 | case NL80211_IFTYPE_MESH_POINT: | ||
| 805 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
| 806 | break; | ||
| 807 | ieee80211_mesh_rx_queued_mgmt(sdata, skb); | ||
| 808 | break; | ||
| 809 | default: | ||
| 810 | WARN(1, "frame for unexpected interface type"); | ||
| 811 | break; | ||
| 812 | } | ||
| 813 | |||
| 814 | kfree_skb(skb); | ||
| 815 | } | ||
| 816 | |||
| 817 | /* then other type-dependent work */ | ||
| 818 | switch (sdata->vif.type) { | ||
| 819 | case NL80211_IFTYPE_STATION: | ||
| 820 | ieee80211_sta_work(sdata); | ||
| 821 | break; | ||
| 822 | case NL80211_IFTYPE_ADHOC: | ||
| 823 | ieee80211_ibss_work(sdata); | ||
| 824 | break; | ||
| 825 | case NL80211_IFTYPE_MESH_POINT: | ||
| 826 | if (!ieee80211_vif_is_mesh(&sdata->vif)) | ||
| 827 | break; | ||
| 828 | ieee80211_mesh_work(sdata); | ||
| 829 | break; | ||
| 830 | default: | ||
| 831 | break; | ||
| 832 | } | ||
| 833 | } | ||
| 834 | |||
| 835 | |||
| 713 | /* | 836 | /* |
| 714 | * Helper function to initialise an interface to a specific type. | 837 | * Helper function to initialise an interface to a specific type. |
| 715 | */ | 838 | */ |
| @@ -727,6 +850,9 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
| 727 | /* only monitor differs */ | 850 | /* only monitor differs */ |
| 728 | sdata->dev->type = ARPHRD_ETHER; | 851 | sdata->dev->type = ARPHRD_ETHER; |
| 729 | 852 | ||
| 853 | skb_queue_head_init(&sdata->skb_queue); | ||
| 854 | INIT_WORK(&sdata->work, ieee80211_iface_work); | ||
| 855 | |||
| 730 | switch (type) { | 856 | switch (type) { |
| 731 | case NL80211_IFTYPE_AP: | 857 | case NL80211_IFTYPE_AP: |
| 732 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); | 858 | skb_queue_head_init(&sdata->u.ap.ps_bc_buf); |
| @@ -779,7 +905,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 779 | * and goes into the requested mode. | 905 | * and goes into the requested mode. |
| 780 | */ | 906 | */ |
| 781 | 907 | ||
| 782 | if (netif_running(sdata->dev)) | 908 | if (ieee80211_sdata_running(sdata)) |
| 783 | return -EBUSY; | 909 | return -EBUSY; |
| 784 | 910 | ||
| 785 | /* Purge and reset type-dependent state. */ | 911 | /* Purge and reset type-dependent state. */ |
| @@ -797,6 +923,118 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | |||
| 797 | return 0; | 923 | return 0; |
| 798 | } | 924 | } |
| 799 | 925 | ||
| 926 | static void ieee80211_assign_perm_addr(struct ieee80211_local *local, | ||
| 927 | struct net_device *dev, | ||
| 928 | enum nl80211_iftype type) | ||
| 929 | { | ||
| 930 | struct ieee80211_sub_if_data *sdata; | ||
| 931 | u64 mask, start, addr, val, inc; | ||
| 932 | u8 *m; | ||
| 933 | u8 tmp_addr[ETH_ALEN]; | ||
| 934 | int i; | ||
| 935 | |||
| 936 | /* default ... something at least */ | ||
| 937 | memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | ||
| 938 | |||
| 939 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask) && | ||
| 940 | local->hw.wiphy->n_addresses <= 1) | ||
| 941 | return; | ||
| 942 | |||
| 943 | |||
| 944 | mutex_lock(&local->iflist_mtx); | ||
| 945 | |||
| 946 | switch (type) { | ||
| 947 | case NL80211_IFTYPE_MONITOR: | ||
| 948 | /* doesn't matter */ | ||
| 949 | break; | ||
| 950 | case NL80211_IFTYPE_WDS: | ||
| 951 | case NL80211_IFTYPE_AP_VLAN: | ||
| 952 | /* match up with an AP interface */ | ||
| 953 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 954 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
| 955 | continue; | ||
| 956 | memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN); | ||
| 957 | break; | ||
| 958 | } | ||
| 959 | /* keep default if no AP interface present */ | ||
| 960 | break; | ||
| 961 | default: | ||
| 962 | /* assign a new address if possible -- try n_addresses first */ | ||
| 963 | for (i = 0; i < local->hw.wiphy->n_addresses; i++) { | ||
| 964 | bool used = false; | ||
| 965 | |||
| 966 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 967 | if (memcmp(local->hw.wiphy->addresses[i].addr, | ||
| 968 | sdata->vif.addr, ETH_ALEN) == 0) { | ||
| 969 | used = true; | ||
| 970 | break; | ||
| 971 | } | ||
| 972 | } | ||
| 973 | |||
| 974 | if (!used) { | ||
| 975 | memcpy(dev->perm_addr, | ||
| 976 | local->hw.wiphy->addresses[i].addr, | ||
| 977 | ETH_ALEN); | ||
| 978 | break; | ||
| 979 | } | ||
| 980 | } | ||
| 981 | |||
| 982 | /* try mask if available */ | ||
| 983 | if (is_zero_ether_addr(local->hw.wiphy->addr_mask)) | ||
| 984 | break; | ||
| 985 | |||
| 986 | m = local->hw.wiphy->addr_mask; | ||
| 987 | mask = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 988 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 989 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 990 | |||
| 991 | if (__ffs64(mask) + hweight64(mask) != fls64(mask)) { | ||
| 992 | /* not a contiguous mask ... not handled now! */ | ||
| 993 | printk(KERN_DEBUG "not contiguous\n"); | ||
| 994 | break; | ||
| 995 | } | ||
| 996 | |||
| 997 | m = local->hw.wiphy->perm_addr; | ||
| 998 | start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) | | ||
| 999 | ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) | | ||
| 1000 | ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8); | ||
| 1001 | |||
| 1002 | inc = 1ULL<<__ffs64(mask); | ||
| 1003 | val = (start & mask); | ||
| 1004 | addr = (start & ~mask) | (val & mask); | ||
| 1005 | do { | ||
| 1006 | bool used = false; | ||
| 1007 | |||
| 1008 | tmp_addr[5] = addr >> 0*8; | ||
| 1009 | tmp_addr[4] = addr >> 1*8; | ||
| 1010 | tmp_addr[3] = addr >> 2*8; | ||
| 1011 | tmp_addr[2] = addr >> 3*8; | ||
| 1012 | tmp_addr[1] = addr >> 4*8; | ||
| 1013 | tmp_addr[0] = addr >> 5*8; | ||
| 1014 | |||
| 1015 | val += inc; | ||
| 1016 | |||
| 1017 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
| 1018 | if (memcmp(tmp_addr, sdata->vif.addr, | ||
| 1019 | ETH_ALEN) == 0) { | ||
| 1020 | used = true; | ||
| 1021 | break; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | if (!used) { | ||
| 1026 | memcpy(dev->perm_addr, tmp_addr, ETH_ALEN); | ||
| 1027 | break; | ||
| 1028 | } | ||
| 1029 | addr = (start & ~mask) | (val & mask); | ||
| 1030 | } while (addr != start); | ||
| 1031 | |||
| 1032 | break; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | mutex_unlock(&local->iflist_mtx); | ||
| 1036 | } | ||
| 1037 | |||
| 800 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, | 1038 | int ieee80211_if_add(struct ieee80211_local *local, const char *name, |
| 801 | struct net_device **new_dev, enum nl80211_iftype type, | 1039 | struct net_device **new_dev, enum nl80211_iftype type, |
| 802 | struct vif_params *params) | 1040 | struct vif_params *params) |
| @@ -826,26 +1064,35 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
| 826 | if (ret < 0) | 1064 | if (ret < 0) |
| 827 | goto fail; | 1065 | goto fail; |
| 828 | 1066 | ||
| 829 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 1067 | ieee80211_assign_perm_addr(local, ndev, type); |
| 830 | memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN); | 1068 | memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); |
| 831 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 1069 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
| 832 | 1070 | ||
| 833 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 1071 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
| 834 | sdata = netdev_priv(ndev); | 1072 | sdata = netdev_priv(ndev); |
| 835 | ndev->ieee80211_ptr = &sdata->wdev; | 1073 | ndev->ieee80211_ptr = &sdata->wdev; |
| 1074 | memcpy(sdata->vif.addr, ndev->dev_addr, ETH_ALEN); | ||
| 1075 | memcpy(sdata->name, ndev->name, IFNAMSIZ); | ||
| 836 | 1076 | ||
| 837 | /* initialise type-independent data */ | 1077 | /* initialise type-independent data */ |
| 838 | sdata->wdev.wiphy = local->hw.wiphy; | 1078 | sdata->wdev.wiphy = local->hw.wiphy; |
| 839 | sdata->local = local; | 1079 | sdata->local = local; |
| 840 | sdata->dev = ndev; | 1080 | sdata->dev = ndev; |
| 1081 | #ifdef CONFIG_INET | ||
| 1082 | sdata->arp_filter_state = true; | ||
| 1083 | #endif | ||
| 841 | 1084 | ||
| 842 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) | 1085 | for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) |
| 843 | skb_queue_head_init(&sdata->fragments[i].skb_list); | 1086 | skb_queue_head_init(&sdata->fragments[i].skb_list); |
| 844 | 1087 | ||
| 845 | INIT_LIST_HEAD(&sdata->key_list); | 1088 | INIT_LIST_HEAD(&sdata->key_list); |
| 846 | 1089 | ||
| 847 | sdata->force_unicast_rateidx = -1; | 1090 | for (i = 0; i < IEEE80211_NUM_BANDS; i++) { |
| 848 | sdata->max_ratectrl_rateidx = -1; | 1091 | struct ieee80211_supported_band *sband; |
| 1092 | sband = local->hw.wiphy->bands[i]; | ||
| 1093 | sdata->rc_rateidx_mask[i] = | ||
| 1094 | sband ? (1 << sband->n_bitrates) - 1 : 0; | ||
| 1095 | } | ||
| 849 | 1096 | ||
| 850 | /* setup type-dependent data */ | 1097 | /* setup type-dependent data */ |
| 851 | ieee80211_setup_sdata(sdata, type); | 1098 | ieee80211_setup_sdata(sdata, type); |
| @@ -938,6 +1185,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | |||
| 938 | wiphy_name(local->hw.wiphy)); | 1185 | wiphy_name(local->hw.wiphy)); |
| 939 | #endif | 1186 | #endif |
| 940 | 1187 | ||
| 1188 | drv_flush(local, false); | ||
| 1189 | |||
| 941 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; | 1190 | local->hw.conf.flags |= IEEE80211_CONF_IDLE; |
| 942 | return IEEE80211_CONF_CHANGE_IDLE; | 1191 | return IEEE80211_CONF_CHANGE_IDLE; |
| 943 | } | 1192 | } |
| @@ -947,16 +1196,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 947 | struct ieee80211_sub_if_data *sdata; | 1196 | struct ieee80211_sub_if_data *sdata; |
| 948 | int count = 0; | 1197 | int count = 0; |
| 949 | 1198 | ||
| 1199 | if (!list_empty(&local->work_list)) | ||
| 1200 | return ieee80211_idle_off(local, "working"); | ||
| 1201 | |||
| 950 | if (local->scanning) | 1202 | if (local->scanning) |
| 951 | return ieee80211_idle_off(local, "scanning"); | 1203 | return ieee80211_idle_off(local, "scanning"); |
| 952 | 1204 | ||
| 953 | list_for_each_entry(sdata, &local->interfaces, list) { | 1205 | list_for_each_entry(sdata, &local->interfaces, list) { |
| 954 | if (!netif_running(sdata->dev)) | 1206 | if (!ieee80211_sdata_running(sdata)) |
| 955 | continue; | 1207 | continue; |
| 956 | /* do not count disabled managed interfaces */ | 1208 | /* do not count disabled managed interfaces */ |
| 957 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 1209 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
| 958 | !sdata->u.mgd.associated && | 1210 | !sdata->u.mgd.associated) |
| 959 | list_empty(&sdata->u.mgd.work_list)) | ||
| 960 | continue; | 1211 | continue; |
| 961 | /* do not count unused IBSS interfaces */ | 1212 | /* do not count unused IBSS interfaces */ |
| 962 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | 1213 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && |
| @@ -984,3 +1235,41 @@ void ieee80211_recalc_idle(struct ieee80211_local *local) | |||
| 984 | if (chg) | 1235 | if (chg) |
| 985 | ieee80211_hw_config(local, chg); | 1236 | ieee80211_hw_config(local, chg); |
| 986 | } | 1237 | } |
| 1238 | |||
| 1239 | static int netdev_notify(struct notifier_block *nb, | ||
| 1240 | unsigned long state, | ||
| 1241 | void *ndev) | ||
| 1242 | { | ||
| 1243 | struct net_device *dev = ndev; | ||
| 1244 | struct ieee80211_sub_if_data *sdata; | ||
| 1245 | |||
| 1246 | if (state != NETDEV_CHANGENAME) | ||
| 1247 | return 0; | ||
| 1248 | |||
| 1249 | if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy) | ||
| 1250 | return 0; | ||
| 1251 | |||
| 1252 | if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid) | ||
| 1253 | return 0; | ||
| 1254 | |||
| 1255 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
| 1256 | |||
| 1257 | memcpy(sdata->name, dev->name, IFNAMSIZ); | ||
| 1258 | |||
| 1259 | ieee80211_debugfs_rename_netdev(sdata); | ||
| 1260 | return 0; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | static struct notifier_block mac80211_netdev_notifier = { | ||
| 1264 | .notifier_call = netdev_notify, | ||
| 1265 | }; | ||
| 1266 | |||
| 1267 | int ieee80211_iface_init(void) | ||
| 1268 | { | ||
| 1269 | return register_netdevice_notifier(&mac80211_netdev_notifier); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | void ieee80211_iface_exit(void) | ||
| 1273 | { | ||
| 1274 | unregister_netdevice_notifier(&mac80211_netdev_notifier); | ||
| 1275 | } | ||
