cfg80211: add cipher capabilities
[safe/jmp/linux-2.6] / net / wireless / nl80211.c
index 44c7997..d33cab0 100644 (file)
@@ -118,6 +118,36 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
        [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
 };
 
+/* IE validation */
+static bool is_valid_ie_attr(const struct nlattr *attr)
+{
+       const u8 *pos;
+       int len;
+
+       if (!attr)
+               return true;
+
+       pos = nla_data(attr);
+       len = nla_len(attr);
+
+       while (len) {
+               u8 elemlen;
+
+               if (len < 2)
+                       return false;
+               len -= 2;
+
+               elemlen = pos[1];
+               if (elemlen > len)
+                       return false;
+
+               len -= elemlen;
+               pos += 2 + elemlen;
+       }
+
+       return true;
+}
+
 /* message building helper */
 static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
                                   int flags, u8 cmd)
@@ -126,6 +156,30 @@ static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
        return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
 }
 
+static int nl80211_msg_put_channel(struct sk_buff *msg,
+                                  struct ieee80211_channel *chan)
+{
+       NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
+                   chan->center_freq);
+
+       if (chan->flags & IEEE80211_CHAN_DISABLED)
+               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
+       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
+       if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
+       if (chan->flags & IEEE80211_CHAN_RADAR)
+               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+
+       NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+                   DBM_TO_MBM(chan->max_power));
+
+       return 0;
+
+ nla_put_failure:
+       return -ENOBUFS;
+}
+
 /* netlink command implementations */
 
 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
@@ -151,6 +205,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
                   dev->wiphy.max_scan_ssids);
+       NLA_PUT_U16(msg, NL80211_ATTR_MAX_SCAN_IE_LEN,
+                   dev->wiphy.max_scan_ie_len);
+
+       NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES,
+               sizeof(u32) * dev->wiphy.n_cipher_suites,
+               dev->wiphy.cipher_suites);
 
        nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
        if (!nl_modes)
@@ -202,20 +262,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                                goto nla_put_failure;
 
                        chan = &dev->wiphy.bands[band]->channels[i];
-                       NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
-                                   chan->center_freq);
 
-                       if (chan->flags & IEEE80211_CHAN_DISABLED)
-                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
-                       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
-                       if (chan->flags & IEEE80211_CHAN_NO_IBSS)
-                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
-                       if (chan->flags & IEEE80211_CHAN_RADAR)
-                               NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
-
-                       NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
-                                   DBM_TO_MBM(chan->max_power));
+                       if (nl80211_msg_put_channel(msg, chan))
+                               goto nla_put_failure;
 
                        nla_nest_end(msg, nl_freq);
                }
@@ -366,16 +415,26 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        int result = 0, rem_txq_params = 0;
        struct nlattr *nl_txq_params;
 
-       rdev = cfg80211_get_dev_from_info(info);
-       if (IS_ERR(rdev))
-               return PTR_ERR(rdev);
+       rtnl_lock();
+
+       mutex_lock(&cfg80211_mutex);
+
+       rdev = __cfg80211_drv_from_info(info);
+       if (IS_ERR(rdev)) {
+               result = PTR_ERR(rdev);
+               goto unlock;
+       }
+
+       mutex_lock(&rdev->mtx);
 
-       if (info->attrs[NL80211_ATTR_WIPHY_NAME]) {
+       if (info->attrs[NL80211_ATTR_WIPHY_NAME])
                result = cfg80211_dev_rename(
                        rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
-               if (result)
-                       goto bad_res;
-       }
+
+       mutex_unlock(&cfg80211_mutex);
+
+       if (result)
+               goto bad_res;
 
        if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) {
                struct ieee80211_txq_params txq_params;
@@ -471,7 +530,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
 
  bad_res:
-       cfg80211_put_dev(rdev);
+       mutex_unlock(&rdev->mtx);
+ unlock:
+       rtnl_unlock();
        return result;
 }
 
@@ -607,6 +668,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        enum nl80211_iftype type;
        struct net_device *dev;
        u32 _flags, *flags = NULL;
+       bool change = false;
 
        memset(&params, 0, sizeof(params));
 
@@ -620,11 +682,17 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
        type = dev->ieee80211_ptr->iftype;
        dev_put(dev);
 
-       err = -EINVAL;
        if (info->attrs[NL80211_ATTR_IFTYPE]) {
-               type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
-               if (type > NL80211_IFTYPE_MAX)
+               enum nl80211_iftype ntype;
+
+               ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
+               if (type != ntype)
+                       change = true;
+               type = ntype;
+               if (type > NL80211_IFTYPE_MAX) {
+                       err = -EINVAL;
                        goto unlock;
+               }
        }
 
        if (!drv->ops->change_virtual_intf ||
@@ -640,6 +708,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                }
                params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
                params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+               change = true;
        }
 
        if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) {
@@ -649,12 +718,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
                }
                err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS],
                                          &_flags);
-               if (!err)
-                       flags = &_flags;
+               if (err)
+                       goto unlock;
+
+               flags = &_flags;
+               change = true;
        }
 
-       err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
-                                           type, flags, &params);
+       if (change)
+               err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+                                                   type, flags, &params);
+       else
+               err = 0;
 
        dev = __dev_get_by_index(&init_net, ifindex);
        WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type));
@@ -908,7 +983,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
-       int err;
+       int err, i;
        struct net_device *dev;
        struct key_params params;
        u8 key_idx = 0;
@@ -977,6 +1052,14 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto unlock_rtnl;
 
+       for (i = 0; i < drv->wiphy.n_cipher_suites; i++)
+               if (params.cipher == drv->wiphy.cipher_suites[i])
+                       break;
+       if (i == drv->wiphy.n_cipher_suites) {
+               err = -EINVAL;
+               goto out;
+       }
+
        if (!drv->ops->add_key) {
                err = -EOPNOTSUPP;
                goto out;
@@ -1043,12 +1126,20 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
        struct beacon_parameters params;
        int haveinfo = 0;
 
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
+               return -EINVAL;
+
        rtnl_lock();
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
                goto unlock_rtnl;
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        switch (info->genlhdr->cmd) {
        case NL80211_CMD_NEW_BEACON:
                /* these are required for NEW_BEACON */
@@ -1136,6 +1227,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
        err = drv->ops->del_beacon(&drv->wiphy, dev);
 
  out:
@@ -1324,7 +1419,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
        }
 
        if (!dev->ops->dump_station) {
-               err = -ENOSYS;
+               err = -EOPNOTSUPP;
                goto out_err;
        }
 
@@ -1556,6 +1651,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
        err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
 
  out:
@@ -1693,10 +1793,15 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
        }
 
        if (!dev->ops->dump_mpath) {
-               err = -ENOSYS;
+               err = -EOPNOTSUPP;
                goto out_err;
        }
 
+       if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        while (1) {
                err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx,
                                           dst, next_hop, &pinfo);
@@ -1754,6 +1859,11 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
        if (err)
                goto out;
@@ -1808,6 +1918,16 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
        err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
 
  out:
@@ -1846,6 +1966,16 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
        err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
 
  out:
@@ -1929,6 +2059,11 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        err = drv->ops->change_bss(&drv->wiphy, dev, &params);
 
  out:
@@ -2367,6 +2502,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        enum ieee80211_band band;
        size_t ie_len;
 
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
        rtnl_lock();
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2380,6 +2518,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
+               goto out;
+       }
+
        if (drv->scan_req) {
                err = -EBUSY;
                goto out;
@@ -2412,6 +2555,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        else
                ie_len = 0;
 
+       if (ie_len > wiphy->max_scan_ie_len) {
+               err = -EINVAL;
+               goto out;
+       }
+
        request = kzalloc(sizeof(*request)
                        + sizeof(*ssid) * n_ssids
                        + sizeof(channel) * n_channels
@@ -2474,7 +2622,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 
        if (info->attrs[NL80211_ATTR_IE]) {
                request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
-               memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]),
+               memcpy((void *)request->ie,
+                      nla_data(info->attrs[NL80211_ATTR_IE]),
                       request->ie_len);
        }
 
@@ -2614,6 +2763,14 @@ static int nl80211_dump_scan(struct sk_buff *skb,
        return err;
 }
 
+static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
+{
+       return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM ||
+               auth_type == NL80211_AUTHTYPE_SHARED_KEY ||
+               auth_type == NL80211_AUTHTYPE_FT ||
+               auth_type == NL80211_AUTHTYPE_NETWORK_EAP;
+}
+
 static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
@@ -2622,6 +2779,15 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        struct wiphy *wiphy;
        int err;
 
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_AUTH_TYPE])
+               return -EINVAL;
+
        rtnl_lock();
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2633,8 +2799,13 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!info->attrs[NL80211_ATTR_MAC]) {
-               err = -EINVAL;
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
                goto out;
        }
 
@@ -2663,9 +2834,10 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                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]);
+       req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
+       if (!nl80211_valid_auth_type(req.auth_type)) {
+               err = -EINVAL;
+               goto out;
        }
 
        err = drv->ops->auth(&drv->wiphy, dev, &req);
@@ -2686,6 +2858,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
        struct wiphy *wiphy;
        int err;
 
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_MAC] ||
+           !info->attrs[NL80211_ATTR_SSID])
+               return -EINVAL;
+
        rtnl_lock();
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2697,9 +2876,13 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!info->attrs[NL80211_ATTR_MAC] ||
-           !info->attrs[NL80211_ATTR_SSID]) {
-               err = -EINVAL;
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
                goto out;
        }
 
@@ -2718,10 +2901,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       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]);
 
@@ -2748,6 +2927,15 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
        struct wiphy *wiphy;
        int err;
 
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_REASON_CODE])
+               return -EINVAL;
+
        rtnl_lock();
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2759,8 +2947,13 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!info->attrs[NL80211_ATTR_MAC]) {
-               err = -EINVAL;
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
                goto out;
        }
 
@@ -2769,9 +2962,12 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 
        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]);
+       req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+       if (req.reason_code == 0) {
+               /* Reason Code 0 is reserved */
+               err = -EINVAL;
+               goto out;
+       }
 
        if (info->attrs[NL80211_ATTR_IE]) {
                req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
@@ -2796,6 +2992,15 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
        struct wiphy *wiphy;
        int err;
 
+       if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!info->attrs[NL80211_ATTR_REASON_CODE])
+               return -EINVAL;
+
        rtnl_lock();
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -2807,8 +3012,13 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       if (!info->attrs[NL80211_ATTR_MAC]) {
-               err = -EINVAL;
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (!netif_running(dev)) {
+               err = -ENETDOWN;
                goto out;
        }
 
@@ -2817,9 +3027,12 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 
        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]);
+       req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
+       if (req.reason_code == 0) {
+               /* Reason Code 0 is reserved */
+               err = -EINVAL;
+               goto out;
+       }
 
        if (info->attrs[NL80211_ATTR_IE]) {
                req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
@@ -3194,7 +3407,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
        struct sk_buff *msg;
        void *hdr;
 
-       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (!msg)
                return;
 
@@ -3213,7 +3426,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
                return;
        }
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_ATOMIC);
        return;
 
  nla_put_failure:
@@ -3235,22 +3448,115 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev,
        nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE);
 }
 
-void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev,
-                           struct net_device *netdev, const u8 *buf,
-                           size_t len)
+void nl80211_send_deauth(struct cfg80211_registered_device *rdev,
+                        struct net_device *netdev, const u8 *buf, size_t len)
 {
        nl80211_send_mlme_event(rdev, netdev, buf, len,
                                NL80211_CMD_DEAUTHENTICATE);
 }
 
-void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev,
-                             struct net_device *netdev, const u8 *buf,
-                             size_t len)
+void nl80211_send_disassoc(struct cfg80211_registered_device *rdev,
+                          struct net_device *netdev, const u8 *buf,
+                          size_t len)
 {
        nl80211_send_mlme_event(rdev, netdev, buf, len,
                                NL80211_CMD_DISASSOCIATE);
 }
 
+void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
+                                struct net_device *netdev, const u8 *addr,
+                                enum nl80211_key_type key_type, int key_id,
+                                const u8 *tsc)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_MICHAEL_MIC_FAILURE);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+       if (addr)
+               NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+       NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE, key_type);
+       NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_id);
+       if (tsc)
+               NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
+void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
+                                   struct ieee80211_channel *channel_before,
+                                   struct ieee80211_channel *channel_after)
+{
+       struct sk_buff *msg;
+       void *hdr;
+       struct nlattr *nl_freq;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_BEACON_HINT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       /*
+        * Since we are applying the beacon hint to a wiphy we know its
+        * wiphy_idx is valid
+        */
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy));
+
+       /* Before */
+       nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_BEFORE);
+       if (!nl_freq)
+               goto nla_put_failure;
+       if (nl80211_msg_put_channel(msg, channel_before))
+               goto nla_put_failure;
+       nla_nest_end(msg, nl_freq);
+
+       /* After */
+       nl_freq = nla_nest_start(msg, NL80211_ATTR_FREQ_AFTER);
+       if (!nl_freq)
+               goto nla_put_failure;
+       if (nl80211_msg_put_channel(msg, channel_after))
+               goto nla_put_failure;
+       nla_nest_end(msg, nl_freq);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
+
+       return;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)