net: phy: dp83848: add dp83822 PHY support
[cascardo/linux.git] / net / wireless / core.c
index 7645e97..8201e6d 100644 (file)
@@ -225,6 +225,23 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
        }
 }
 
+void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
+                      struct wireless_dev *wdev)
+{
+       ASSERT_RTNL();
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_NAN))
+               return;
+
+       if (!wdev->nan_started)
+               return;
+
+       rdev_stop_nan(rdev, wdev);
+       wdev->nan_started = false;
+
+       rdev->opencount--;
+}
+
 void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -242,6 +259,9 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
                case NL80211_IFTYPE_P2P_DEVICE:
                        cfg80211_stop_p2p_device(rdev, wdev);
                        break;
+               case NL80211_IFTYPE_NAN:
+                       cfg80211_stop_nan(rdev, wdev);
+                       break;
                default:
                        break;
                }
@@ -537,6 +557,11 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
                                    c->limits[j].max > 1))
                                return -EINVAL;
 
+                       /* Only a single NAN can be allowed */
+                       if (WARN_ON(types & BIT(NL80211_IFTYPE_NAN) &&
+                                   c->limits[j].max > 1))
+                               return -EINVAL;
+
                        cnt += c->limits[j].max;
                        /*
                         * Don't advertise an unsupported type
@@ -579,6 +604,11 @@ int wiphy_register(struct wiphy *wiphy)
                     !rdev->ops->tdls_cancel_channel_switch)))
                return -EINVAL;
 
+       if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_NAN)) &&
+                   (!rdev->ops->start_nan || !rdev->ops->stop_nan ||
+                    !rdev->ops->add_nan_func || !rdev->ops->del_nan_func)))
+               return -EINVAL;
+
        /*
         * if a wiphy has unsupported modes for regulatory channel enforcement,
         * opt-out of enforcement checking
@@ -589,6 +619,7 @@ int wiphy_register(struct wiphy *wiphy)
                                       BIT(NL80211_IFTYPE_P2P_GO) |
                                       BIT(NL80211_IFTYPE_ADHOC) |
                                       BIT(NL80211_IFTYPE_P2P_DEVICE) |
+                                      BIT(NL80211_IFTYPE_NAN) |
                                       BIT(NL80211_IFTYPE_AP_VLAN) |
                                       BIT(NL80211_IFTYPE_MONITOR)))
                wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
@@ -906,6 +937,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
        if (WARN_ON(wdev->netdev))
                return;
 
+       nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
+
        list_del_rcu(&wdev->list);
        rdev->devlist_generation++;
 
@@ -914,6 +947,9 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
                cfg80211_mlme_purge_registrations(wdev);
                cfg80211_stop_p2p_device(rdev, wdev);
                break;
+       case NL80211_IFTYPE_NAN:
+               cfg80211_stop_nan(rdev, wdev);
+               break;
        default:
                WARN_ON_ONCE(1);
                break;
@@ -977,6 +1013,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
                /* must be handled by mac80211/driver, has no APIs */
                break;
        case NL80211_IFTYPE_P2P_DEVICE:
+       case NL80211_IFTYPE_NAN:
                /* cannot happen, has no netdev */
                break;
        case NL80211_IFTYPE_AP_VLAN:
@@ -1079,6 +1116,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                     wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
                     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
                        dev->priv_flags |= IFF_DONT_BRIDGE;
+
+               nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
                break;
        case NETDEV_GOING_DOWN:
                cfg80211_leave(rdev, wdev);
@@ -1157,6 +1196,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                 * remove and clean it up.
                 */
                if (!list_empty(&wdev->list)) {
+                       nl80211_notify_iface(rdev, wdev,
+                                            NL80211_CMD_DEL_INTERFACE);
                        sysfs_remove_link(&dev->dev.kobj, "phy80211");
                        list_del_rcu(&wdev->list);
                        rdev->devlist_generation++;
@@ -1246,7 +1287,7 @@ static int __init cfg80211_init(void)
        if (err)
                goto out_fail_reg;
 
-       cfg80211_wq = create_singlethread_workqueue("cfg80211");
+       cfg80211_wq = alloc_ordered_workqueue("cfg80211", WQ_MEM_RECLAIM);
        if (!cfg80211_wq) {
                err = -ENOMEM;
                goto out_fail_wq;