Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / net / mac80211 / iface.c
index e469b33..9df26ad 100644 (file)
@@ -258,6 +258,15 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
        /* we hold the RTNL here so can safely walk the list */
        list_for_each_entry(nsdata, &local->interfaces, list) {
                if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
+                       /*
+                        * Only OCB and monitor mode may coexist
+                        */
+                       if ((sdata->vif.type == NL80211_IFTYPE_OCB &&
+                            nsdata->vif.type != NL80211_IFTYPE_MONITOR) ||
+                           (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+                            nsdata->vif.type == NL80211_IFTYPE_OCB))
+                               return -EBUSY;
+
                        /*
                         * Allow only a single IBSS interface to be up at any
                         * time. This is restricted because beacon distribution
@@ -521,6 +530,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_P2P_DEVICE:
+       case NL80211_IFTYPE_OCB:
                /* no special treatment */
                break;
        case NL80211_IFTYPE_UNSPECIFIED:
@@ -631,6 +641,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_MESH_POINT:
+               case NL80211_IFTYPE_OCB:
                        netif_carrier_off(dev);
                        break;
                case NL80211_IFTYPE_WDS:
@@ -766,10 +777,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        int i, flushed;
        struct ps_data *ps;
        struct cfg80211_chan_def chandef;
+       bool cancel_scan;
 
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
-       if (rcu_access_pointer(local->scan_sdata) == sdata)
+       cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
+       if (cancel_scan)
                ieee80211_scan_cancel(local);
 
        /*
@@ -900,6 +913,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                list_del(&sdata->u.vlan.list);
                mutex_unlock(&local->mtx);
                RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
+               /* see comment in the default case below */
+               ieee80211_free_keys(sdata, true);
                /* no need to tell driver */
                break;
        case NL80211_IFTYPE_MONITOR:
@@ -925,17 +940,16 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                /*
                 * When we get here, the interface is marked down.
                 * Free the remaining keys, if there are any
-                * (shouldn't be, except maybe in WDS mode?)
+                * (which can happen in AP mode if userspace sets
+                * keys before the interface is operating, and maybe
+                * also in WDS mode)
                 *
                 * Force the key freeing to always synchronize_net()
                 * to wait for the RX path in case it is using this
-                * interface enqueuing frames at this very time on
+                * interface enqueuing frames at this very time on
                 * another CPU.
                 */
                ieee80211_free_keys(sdata, true);
-
-               /* fall through */
-       case NL80211_IFTYPE_AP:
                skb_queue_purge(&sdata->skb_queue);
        }
 
@@ -993,6 +1007,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_recalc_ps(local, -1);
 
+       if (cancel_scan)
+               flush_delayed_work(&local->scan_work);
+
        if (local->open_count == 0) {
                ieee80211_stop_device(local);
 
@@ -1281,6 +1298,9 @@ static void ieee80211_iface_work(struct work_struct *work)
                        break;
                ieee80211_mesh_work(sdata);
                break;
+       case NL80211_IFTYPE_OCB:
+               ieee80211_ocb_work(sdata);
+               break;
        default:
                break;
        }
@@ -1300,6 +1320,9 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
 static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                                  enum nl80211_iftype type)
 {
+       static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff,
+                                                   0xff, 0xff, 0xff};
+
        /* clear type-dependent union */
        memset(&sdata->u, 0, sizeof(sdata->u));
 
@@ -1351,6 +1374,10 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
                ieee80211_sta_setup_sdata(sdata);
                break;
+       case NL80211_IFTYPE_OCB:
+               sdata->vif.bss_conf.bssid = bssid_wildcard;
+               ieee80211_ocb_setup_sdata(sdata);
+               break;
        case NL80211_IFTYPE_ADHOC:
                sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
                ieee80211_ibss_setup_sdata(sdata);
@@ -1398,6 +1425,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_OCB:
                /*
                 * Could maybe also all others here?
                 * Just not sure how that interacts
@@ -1413,6 +1441,7 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_OCB:
                /*
                 * Could probably support everything
                 * but WDS here (WDS do_open can fail
@@ -1671,7 +1700,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                }
 
                ieee80211_assign_perm_addr(local, ndev->perm_addr, type);
-               memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
+               if (params && is_valid_ether_addr(params->macaddr))
+                       memcpy(ndev->dev_addr, params->macaddr, ETH_ALEN);
+               else
+                       memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
                SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
 
                /* don't use IEEE80211_DEV_TO_SUB_IF -- it checks too much */