|
@@ -409,6 +409,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
|
|
.len = VHT_MUMIMO_GROUPS_DATA_LEN
|
|
|
},
|
|
|
[NL80211_ATTR_MU_MIMO_FOLLOW_MAC_ADDR] = { .len = ETH_ALEN },
|
|
|
+ [NL80211_ATTR_NAN_MASTER_PREF] = { .type = NLA_U8 },
|
|
|
+ [NL80211_ATTR_NAN_DUAL] = { .type = NLA_U8 },
|
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
@@ -934,6 +936,7 @@ static int nl80211_key_allowed(struct wireless_dev *wdev)
|
|
|
case NL80211_IFTYPE_UNSPECIFIED:
|
|
|
case NL80211_IFTYPE_OCB:
|
|
|
case NL80211_IFTYPE_MONITOR:
|
|
|
+ case NL80211_IFTYPE_NAN:
|
|
|
case NL80211_IFTYPE_P2P_DEVICE:
|
|
|
case NL80211_IFTYPE_WDS:
|
|
|
case NUM_NL80211_IFTYPES:
|
|
@@ -2819,7 +2822,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|
|
!(rdev->wiphy.interface_modes & (1 << type)))
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
- if ((type == NL80211_IFTYPE_P2P_DEVICE ||
|
|
|
+ if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
|
|
|
rdev->wiphy.features & NL80211_FEATURE_MAC_ON_CREATE) &&
|
|
|
info->attrs[NL80211_ATTR_MAC]) {
|
|
|
nla_memcpy(params.macaddr, info->attrs[NL80211_ATTR_MAC],
|
|
@@ -2875,9 +2878,10 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|
|
wdev->mesh_id_up_len);
|
|
|
wdev_unlock(wdev);
|
|
|
break;
|
|
|
+ case NL80211_IFTYPE_NAN:
|
|
|
case NL80211_IFTYPE_P2P_DEVICE:
|
|
|
/*
|
|
|
- * P2P Device doesn't have a netdev, so doesn't go
|
|
|
+ * P2P Device and NAN do not have a netdev, so don't go
|
|
|
* through the netdev notifier and must be added here
|
|
|
*/
|
|
|
mutex_init(&wdev->mtx);
|
|
@@ -6434,6 +6438,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
|
|
|
|
|
|
wiphy = &rdev->wiphy;
|
|
|
|
|
|
+ if (wdev->iftype == NL80211_IFTYPE_NAN)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
if (!rdev->ops->scan)
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
@@ -8977,6 +8984,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
|
case NL80211_IFTYPE_P2P_DEVICE:
|
|
|
break;
|
|
|
+ case NL80211_IFTYPE_NAN:
|
|
|
default:
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
@@ -9022,6 +9030,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
|
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
|
break;
|
|
|
+ case NL80211_IFTYPE_NAN:
|
|
|
default:
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
@@ -9138,6 +9147,7 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
|
|
|
case NL80211_IFTYPE_P2P_GO:
|
|
|
case NL80211_IFTYPE_P2P_DEVICE:
|
|
|
break;
|
|
|
+ case NL80211_IFTYPE_NAN:
|
|
|
default:
|
|
|
return -EOPNOTSUPP;
|
|
|
}
|
|
@@ -10504,6 +10514,58 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int nl80211_start_nan(struct sk_buff *skb, struct genl_info *info)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+ struct wireless_dev *wdev = info->user_ptr[1];
|
|
|
+ struct cfg80211_nan_conf conf = {};
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_NAN)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ if (wdev->nan_started)
|
|
|
+ return -EEXIST;
|
|
|
+
|
|
|
+ if (rfkill_blocked(rdev->rfkill))
|
|
|
+ return -ERFKILL;
|
|
|
+
|
|
|
+ if (!info->attrs[NL80211_ATTR_NAN_MASTER_PREF])
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!info->attrs[NL80211_ATTR_NAN_DUAL])
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ conf.master_pref =
|
|
|
+ nla_get_u8(info->attrs[NL80211_ATTR_NAN_MASTER_PREF]);
|
|
|
+ if (!conf.master_pref)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ conf.dual = nla_get_u8(info->attrs[NL80211_ATTR_NAN_DUAL]);
|
|
|
+
|
|
|
+ err = rdev_start_nan(rdev, wdev, &conf);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ wdev->nan_started = true;
|
|
|
+ rdev->opencount++;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int nl80211_stop_nan(struct sk_buff *skb, struct genl_info *info)
|
|
|
+{
|
|
|
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
|
|
+ struct wireless_dev *wdev = info->user_ptr[1];
|
|
|
+
|
|
|
+ if (wdev->iftype != NL80211_IFTYPE_NAN)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ cfg80211_stop_nan(rdev, wdev);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int nl80211_get_protocol_features(struct sk_buff *skb,
|
|
|
struct genl_info *info)
|
|
|
{
|
|
@@ -11205,7 +11267,14 @@ static int nl80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
|
|
|
|
|
|
dev_hold(dev);
|
|
|
} else if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP) {
|
|
|
- if (!wdev->p2p_started) {
|
|
|
+ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
|
|
|
+ !wdev->p2p_started) {
|
|
|
+ if (rtnl)
|
|
|
+ rtnl_unlock();
|
|
|
+ return -ENETDOWN;
|
|
|
+ }
|
|
|
+ if (wdev->iftype == NL80211_IFTYPE_NAN &&
|
|
|
+ !wdev->nan_started) {
|
|
|
if (rtnl)
|
|
|
rtnl_unlock();
|
|
|
return -ENETDOWN;
|
|
@@ -11838,6 +11907,22 @@ static const struct genl_ops nl80211_ops[] = {
|
|
|
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
|
|
NL80211_FLAG_NEED_RTNL,
|
|
|
},
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_START_NAN,
|
|
|
+ .doit = nl80211_start_nan,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_WDEV |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .cmd = NL80211_CMD_STOP_NAN,
|
|
|
+ .doit = nl80211_stop_nan,
|
|
|
+ .policy = nl80211_policy,
|
|
|
+ .flags = GENL_ADMIN_PERM,
|
|
|
+ .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
|
|
|
+ NL80211_FLAG_NEED_RTNL,
|
|
|
+ },
|
|
|
{
|
|
|
.cmd = NL80211_CMD_SET_MCAST_RATE,
|
|
|
.doit = nl80211_set_mcast_rate,
|