+static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ struct cfg80211_auth_request req;
+ struct wiphy *wiphy;
+ int err;
+
+ rtnl_lock();
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (!drv->ops->auth) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!info->attrs[NL80211_ATTR_MAC]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ wiphy = &drv->wiphy;
+ memset(&req, 0, sizeof(req));
+
+ req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ req.chan = ieee80211_get_channel(
+ wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (!req.chan) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (info->attrs[NL80211_ATTR_SSID]) {
+ req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+ }
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
+ req.auth_type =
+ nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+ }
+
+ err = drv->ops->auth(&drv->wiphy, dev, &req);
+
+out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ struct cfg80211_assoc_request req;
+ struct wiphy *wiphy;
+ int err;
+
+ rtnl_lock();
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (!drv->ops->assoc) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!info->attrs[NL80211_ATTR_MAC] ||
+ !info->attrs[NL80211_ATTR_SSID]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ wiphy = &drv->wiphy;
+ memset(&req, 0, sizeof(req));
+
+ req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ req.chan = ieee80211_get_channel(
+ wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
+ if (!req.chan) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (nla_len(info->attrs[NL80211_ATTR_SSID]) > IEEE80211_MAX_SSID_LEN) {
+ err = -EINVAL;
+ goto out;
+ }
+ req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ err = drv->ops->assoc(&drv->wiphy, dev, &req);
+
+out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ struct cfg80211_deauth_request req;
+ struct wiphy *wiphy;
+ int err;
+
+ rtnl_lock();
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (!drv->ops->deauth) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!info->attrs[NL80211_ATTR_MAC]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ wiphy = &drv->wiphy;
+ memset(&req, 0, sizeof(req));
+
+ req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_REASON_CODE])
+ req.reason_code =
+ nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ err = drv->ops->deauth(&drv->wiphy, dev, &req);
+
+out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+
+static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *drv;
+ struct net_device *dev;
+ struct cfg80211_disassoc_request req;
+ struct wiphy *wiphy;
+ int err;
+
+ rtnl_lock();
+
+ err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
+ if (err)
+ goto unlock_rtnl;
+
+ if (!drv->ops->disassoc) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!info->attrs[NL80211_ATTR_MAC]) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ wiphy = &drv->wiphy;
+ memset(&req, 0, sizeof(req));
+
+ req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ if (info->attrs[NL80211_ATTR_REASON_CODE])
+ req.reason_code =
+ nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
+ req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ }
+
+ err = drv->ops->disassoc(&drv->wiphy, dev, &req);
+
+out:
+ cfg80211_put_dev(drv);
+ dev_put(dev);
+unlock_rtnl:
+ rtnl_unlock();
+ return err;
+}
+