aboutsummaryrefslogtreecommitdiffstats
path: root/package/mac80211/src/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/src/wireless/nl80211.c')
-rw-r--r--package/mac80211/src/wireless/nl80211.c919
1 files changed, 178 insertions, 741 deletions
diff --git a/package/mac80211/src/wireless/nl80211.c b/package/mac80211/src/wireless/nl80211.c
index ffbe6288a2..58717f3037 100644
--- a/package/mac80211/src/wireless/nl80211.c
+++ b/package/mac80211/src/wireless/nl80211.c
@@ -1,7 +1,7 @@
/*
* This is the new netlink-based wireless configuration interface.
*
- * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/if.h>
@@ -13,6 +13,7 @@
#include <linux/ieee80211.h>
#include <linux/nl80211.h>
#include <linux/rtnetlink.h>
+#include <linux/netlink.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
#include "core.h"
@@ -27,22 +28,6 @@ static struct genl_family nl80211_fam = {
.maxattr = NL80211_ATTR_MAX,
};
-/* internal helper: validate an information element attribute */
-static int check_information_element(struct nlattr *nla)
-{
- int len = nla_len(nla);
- u8 *data = nla_data(nla);
- int elementlen;
-
- while (len >= 2) {
- /* 1 byte ID, 1 byte len, `len' bytes data */
- elementlen = *(data+1) + 2;
- data += elementlen;
- len -= elementlen;
- }
- return len ? -EINVAL : 0;
-}
-
/* internal helper: get drv and dev */
static int get_drv_dev_by_info_ifindex(struct genl_info *info,
struct cfg80211_registered_device **drv,
@@ -55,7 +40,7 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
*dev = dev_get_by_index(ifindex);
- if (!dev)
+ if (!*dev)
return -ENODEV;
*drv = cfg80211_get_dev_from_ifindex(ifindex);
@@ -69,287 +54,194 @@ static int get_drv_dev_by_info_ifindex(struct genl_info *info,
/* policy for the attributes */
static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
- [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
- [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = BUS_ID_SIZE-1 },
+
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
- [NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
- [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
- .len = IEEE80211_MAX_SSID_LEN },
- [NL80211_ATTR_CHANNEL] = { .type = NLA_U32 },
- [NL80211_ATTR_PHYMODE] = { .type = NLA_U32 },
- [NL80211_ATTR_CHANNEL_LIST] = { .type = NLA_NESTED },
- [NL80211_ATTR_BSS_LIST] = { .type = NLA_NESTED },
- [NL80211_ATTR_BSSTYPE] = { .type = NLA_U32 },
- [NL80211_ATTR_BEACON_PERIOD] = { .type = NLA_U32 },
- [NL80211_ATTR_DTIM_PERIOD] = { .type = NLA_U32 },
- [NL80211_ATTR_TIMESTAMP] = { .type = NLA_U64 },
- [NL80211_ATTR_IE] = { .type = NLA_BINARY, .len = NL80211_MAX_IE_LEN },
- [NL80211_ATTR_AUTH_ALGORITHM] = { .type = NLA_U32 },
- [NL80211_ATTR_TIMEOUT_TU] = { .type = NLA_U32 },
- [NL80211_ATTR_REASON_CODE] = { .type = NLA_U32 },
- [NL80211_ATTR_ASSOCIATION_ID] = { .type = NLA_U16 },
- [NL80211_ATTR_DEAUTHENTICATED] = { .type = NLA_FLAG },
- [NL80211_ATTR_RX_SENSITIVITY] = { .type = NLA_U32 },
- [NL80211_ATTR_TRANSMIT_POWER] = { .type = NLA_U32 },
- [NL80211_ATTR_FRAG_THRESHOLD] = { .type = NLA_U32 },
- [NL80211_ATTR_FLAG_SCAN_ACTIVE] = { .type = NLA_FLAG },
- [NL80211_ATTR_BEACON_HEAD] = { .type = NLA_BINARY },
- [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY },
- [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
- .len = WLAN_MAX_KEY_LEN },
- [NL80211_ATTR_KEY_ID] = { .type = NLA_U32 },
- [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
- [NL80211_ATTR_MAC] = { .len = ETH_ALEN },
- [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
+ [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
+ [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
};
-/* netlink command implementations */
+/* message building helper */
+static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
+ int flags, u8 cmd)
+{
+ /* since there is no private header just add the generic one */
+ return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
+}
-#define CHECK_CMD(ptr, cmd) \
- if (drv->ops->ptr) \
- NLA_PUT_FLAG(msg, NL80211_CMD_##cmd);
+/* netlink command implementations */
-static int nl80211_get_cmdlist(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+ struct cfg80211_registered_device *dev)
{
- struct cfg80211_registered_device *drv;
- struct sk_buff *msg;
void *hdr;
- int err;
- struct nlattr *start;
- drv = cfg80211_get_dev_from_info(info);
- if (IS_ERR(drv))
- return PTR_ERR(drv);
-
- hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
- NL80211_CMD_NEW_CMDLIST);
- if (IS_ERR(hdr)) {
- err = PTR_ERR(hdr);
- goto put_drv;
- }
+ hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
+ if (!hdr)
+ return -1;
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
+ NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+ return genlmsg_end(msg, hdr);
- start = nla_nest_start(msg, NL80211_ATTR_CMDS);
- if (!start)
- goto nla_put_failure;
-
- /* unconditionally allow some common commands we handle centrally
- * or where we require the implementation */
- NLA_PUT_FLAG(msg, NL80211_CMD_GET_CMDLIST);
- NLA_PUT_FLAG(msg, NL80211_CMD_GET_WIPHYS);
- NLA_PUT_FLAG(msg, NL80211_CMD_GET_INTERFACES);
- NLA_PUT_FLAG(msg, NL80211_CMD_RENAME_WIPHY);
-
- CHECK_CMD(add_virtual_intf, ADD_VIRTUAL_INTERFACE);
- CHECK_CMD(del_virtual_intf, DEL_VIRTUAL_INTERFACE);
- CHECK_CMD(associate, ASSOCIATE);
- CHECK_CMD(disassociate, DISASSOCIATE);
- CHECK_CMD(deauth, DEAUTH);
- CHECK_CMD(initiate_scan, INITIATE_SCAN);
- CHECK_CMD(get_association, GET_ASSOCIATION);
- CHECK_CMD(get_auth_list, GET_AUTH_LIST);
- CHECK_CMD(add_key, ADD_KEY);
- CHECK_CMD(del_key, DEL_KEY);
+ nla_put_failure:
+ return genlmsg_cancel(msg, hdr);
+}
- nla_nest_end(msg, start);
+static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx = 0;
+ int start = cb->args[0];
+ struct cfg80211_registered_device *dev;
- genlmsg_end(msg, hdr);
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ if (++idx < start)
+ continue;
+ if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ dev) < 0)
+ break;
+ }
+ mutex_unlock(&cfg80211_drv_mutex);
- err = genlmsg_unicast(msg, info->snd_pid);
- goto put_drv;
+ cb->args[0] = idx;
- nla_put_failure:
- err = -ENOBUFS;
- nlmsg_free(msg);
- put_drv:
- cfg80211_put_dev(drv);
- return err;
+ return skb->len;
}
-#undef CHECK_CMD
-static int nl80211_get_wiphys(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
- void *hdr;
- struct nlattr *start, *indexstart;
- struct cfg80211_registered_device *drv;
- int idx = 1;
-
- hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
- NL80211_CMD_NEW_WIPHYS);
- if (IS_ERR(hdr))
- return PTR_ERR(hdr);
+ struct cfg80211_registered_device *dev;
- start = nla_nest_start(msg, NL80211_ATTR_WIPHY_LIST);
- if (!start)
- goto nla_outer_nest_failure;
+ dev = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(dev))
+ return PTR_ERR(dev);
- mutex_lock(&cfg80211_drv_mutex);
- list_for_each_entry(drv, &cfg80211_drv_list, list) {
- indexstart = nla_nest_start(msg, idx++);
- if (!indexstart)
- goto nla_put_failure;
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
- nla_nest_end(msg, indexstart);
- }
- mutex_unlock(&cfg80211_drv_mutex);
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ goto out_err;
- nla_nest_end(msg, start);
+ if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
+ goto out_free;
- genlmsg_end(msg, hdr);
+ cfg80211_put_dev(dev);
return genlmsg_unicast(msg, info->snd_pid);
- nla_put_failure:
- mutex_unlock(&cfg80211_drv_mutex);
- nla_outer_nest_failure:
+ out_free:
nlmsg_free(msg);
+ out_err:
+ cfg80211_put_dev(dev);
return -ENOBUFS;
}
-static int addifidx(struct net_device *dev, struct sk_buff *skb, int *idx)
+static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
{
- int err = -ENOBUFS;
- struct nlattr *start;
-
- dev_hold(dev);
+ struct cfg80211_registered_device *rdev;
+ int result;
- start = nla_nest_start(skb, *idx++);
- if (!start)
- goto nla_put_failure;
+ if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
+ return -EINVAL;
- NLA_PUT_U32(skb, NL80211_ATTR_IFINDEX, dev->ifindex);
- NLA_PUT_STRING(skb, NL80211_ATTR_IFNAME, dev->name);
+ rdev = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
- nla_nest_end(skb, start);
- err = 0;
+ result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
- nla_put_failure:
- dev_put(dev);
- return err;
+ cfg80211_put_dev(rdev);
+ return result;
}
-static int nl80211_get_intfs(struct sk_buff *skb, struct genl_info *info)
+
+static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
+ struct net_device *dev)
{
- struct cfg80211_registered_device *drv;
- struct sk_buff *msg;
void *hdr;
- int err, array_idx;
- struct nlattr *start;
- struct wireless_dev *wdev;
-
- drv = cfg80211_get_dev_from_info(info);
- if (IS_ERR(drv))
- return PTR_ERR(drv);
-
- hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
- NL80211_CMD_NEW_INTERFACES);
- if (IS_ERR(hdr)) {
- err = PTR_ERR(hdr);
- goto put_drv;
- }
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, drv->idx);
+ hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
+ if (!hdr)
+ return -1;
- start = nla_nest_start(msg, NL80211_ATTR_INTERFACE_LIST);
- if (!start) {
- err = -ENOBUFS;
- goto msg_free;
- }
-
- array_idx = 1;
- err = 0;
- mutex_lock(&drv->devlist_mtx);
- list_for_each_entry(wdev, &drv->netdev_list, list) {
- err = addifidx(wdev->netdev, msg, &array_idx);
- if (err)
- break;
- }
- mutex_unlock(&drv->devlist_mtx);
- if (err)
- goto msg_free;
-
- nla_nest_end(msg, start);
-
- genlmsg_end(msg, hdr);
-
- err = genlmsg_unicast(msg, info->snd_pid);
- goto put_drv;
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
+ /* TODO: interface type */
+ return genlmsg_end(msg, hdr);
nla_put_failure:
- err = -ENOBUFS;
- msg_free:
- nlmsg_free(msg);
- put_drv:
- cfg80211_put_dev(drv);
- return err;
+ return genlmsg_cancel(msg, hdr);
}
-static int nl80211_add_virt_intf(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct cfg80211_registered_device *drv;
- int err;
- enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
-
- if (!info->attrs[NL80211_ATTR_IFNAME])
- return -EINVAL;
+ int wp_idx = 0;
+ int if_idx = 0;
+ int wp_start = cb->args[0];
+ int if_start = cb->args[1];
+ struct cfg80211_registered_device *dev;
+ struct wireless_dev *wdev;
- if (info->attrs[NL80211_ATTR_IFTYPE]) {
- type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
- if (type > NL80211_IFTYPE_MAX)
- return -EINVAL;
+ mutex_lock(&cfg80211_drv_mutex);
+ list_for_each_entry(dev, &cfg80211_drv_list, list) {
+ if (++wp_idx < wp_start)
+ continue;
+ if_idx = 0;
+
+ mutex_lock(&dev->devlist_mtx);
+ list_for_each_entry(wdev, &dev->netdev_list, list) {
+ if (++if_idx < if_start)
+ continue;
+ if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ wdev->netdev) < 0)
+ break;
+ }
+ mutex_unlock(&dev->devlist_mtx);
}
+ mutex_unlock(&cfg80211_drv_mutex);
- drv = cfg80211_get_dev_from_info(info);
- if (IS_ERR(drv))
- return PTR_ERR(drv);
-
- if (!drv->ops->add_virtual_intf) {
- err = -EOPNOTSUPP;
- goto unlock;
- }
+ cb->args[0] = wp_idx;
+ cb->args[1] = if_idx;
- rtnl_lock();
- err = drv->ops->add_virtual_intf(&drv->wiphy,
- nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
- rtnl_unlock();
-
- unlock:
- cfg80211_put_dev(drv);
- return err;
+ return skb->len;
}
-static int nl80211_del_virt_intf(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
{
- struct cfg80211_registered_device *drv;
- int ifindex, err;
- struct net_device *dev;
+ struct sk_buff *msg;
+ struct cfg80211_registered_device *dev;
+ struct net_device *netdev;
+ int err;
- err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+ err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
if (err)
return err;
- ifindex = dev->ifindex;
- dev_put(dev);
- if (!drv->ops->del_virtual_intf) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ goto out_err;
- rtnl_lock();
- err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
- rtnl_unlock();
+ if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
+ goto out_free;
- out:
- cfg80211_put_dev(drv);
- return err;
+ dev_put(netdev);
+ cfg80211_put_dev(dev);
+
+ return genlmsg_unicast(msg, info->snd_pid);
+
+ out_free:
+ nlmsg_free(msg);
+ out_err:
+ dev_put(netdev);
+ cfg80211_put_dev(dev);
+ return -ENOBUFS;
}
-static int nl80211_change_virt_intf(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err, ifindex;
@@ -383,588 +275,128 @@ static int nl80211_change_virt_intf(struct sk_buff *skb, struct genl_info *info)
return err;
}
-static int nl80211_get_association(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
int err;
- struct net_device *dev;
- struct sk_buff *msg;
- void *hdr;
- u8 bssid[ETH_ALEN];
-
- err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
- if (err)
- return err;
-
- if (!drv->ops->get_association) {
- err = -EOPNOTSUPP;
- goto out_put_drv;
- }
-
- rtnl_lock();
- err = drv->ops->get_association(&drv->wiphy, dev, bssid);
- rtnl_unlock();
- if (err < 0)
- goto out_put_drv;
-
- hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
- NL80211_CMD_ASSOCIATION_CHANGED);
-
- if (IS_ERR(hdr)) {
- err = PTR_ERR(hdr);
- goto out_put_drv;
- }
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
- if (err == 1)
- NLA_PUT(msg, NL80211_ATTR_BSSID, ETH_ALEN, bssid);
-
- genlmsg_end(msg, hdr);
- err = genlmsg_unicast(msg, info->snd_pid);
- goto out_put_drv;
-
- nla_put_failure:
- err = -ENOBUFS;
- nlmsg_free(msg);
- out_put_drv:
- cfg80211_put_dev(drv);
- dev_put(dev);
- return err;
-}
-
-static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
-{
- struct cfg80211_registered_device *drv;
- int err;
- struct net_device *dev;
- struct association_params assoc_params;
-
- memset(&assoc_params, 0, sizeof(assoc_params));
-
- err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
- if (err)
- return err;
-
- if (!drv->ops->associate) {
- err = -EOPNOTSUPP;
- goto out;
- }
+ enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
- if (!info->attrs[NL80211_ATTR_SSID])
+ if (!info->attrs[NL80211_ATTR_IFNAME])
return -EINVAL;
- assoc_params.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
- assoc_params.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
-
- if (info->attrs[NL80211_ATTR_BSSID])
- assoc_params.bssid = nla_data(info->attrs[NL80211_ATTR_BSSID]);
-
- if (info->attrs[NL80211_ATTR_IE]) {
- err = check_information_element(info->attrs[NL80211_ATTR_IE]);
- if (err)
- goto out;
- assoc_params.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
- assoc_params.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
- }
-
- if (info->attrs[NL80211_ATTR_TIMEOUT_TU]) {
- assoc_params.timeout =
- nla_get_u32(info->attrs[NL80211_ATTR_TIMEOUT_TU]);
- assoc_params.valid |= ASSOC_PARAMS_TIMEOUT;
- }
-
- rtnl_lock();
- err = drv->ops->associate(&drv->wiphy, dev, &assoc_params);
- rtnl_unlock();
-
- out:
- cfg80211_put_dev(drv);
- dev_put(dev);
- return err;
-}
-
-static int nl80211_disassoc_deauth(struct sk_buff *skb, struct genl_info *info)
-{
- struct cfg80211_registered_device *drv;
- int err;
- struct net_device *dev;
- int (*act)(struct wiphy *wiphy, struct net_device *dev);
-
- err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
- if (err)
- return err;
-
- switch (info->genlhdr->cmd) {
- case NL80211_CMD_DISASSOCIATE:
- act = drv->ops->disassociate;
- break;
- case NL80211_CMD_DEAUTH:
- act = drv->ops->deauth;
- break;
- default:
- act = NULL;
- }
-
- if (!act) {
- err = -EOPNOTSUPP;
- goto out;
+ if (info->attrs[NL80211_ATTR_IFTYPE]) {
+ type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
+ if (type > NL80211_IFTYPE_MAX)
+ return -EINVAL;
}
- rtnl_lock();
- err = act(&drv->wiphy, dev);
- rtnl_unlock();
- out:
- cfg80211_put_dev(drv);
- dev_put(dev);
- return err;
-}
-
-struct add_cb_data {
- int idx;
- struct sk_buff *skb;
-};
-
-static int add_bssid(void *data, u8 *bssid)
-{
- struct add_cb_data *cb = data;
- int err = -ENOBUFS;
- struct nlattr *start;
-
- start = nla_nest_start(cb->skb, cb->idx++);
- if (!start)
- goto nla_put_failure;
-
- NLA_PUT(cb->skb, NL80211_ATTR_BSSID, ETH_ALEN, bssid);
-
- nla_nest_end(cb->skb, start);
- err = 0;
-
- nla_put_failure:
- return err;
-}
-
-static int nl80211_get_auth_list(struct sk_buff *skb, struct genl_info *info)
-{
- struct cfg80211_registered_device *drv;
- struct net_device *dev;
- struct sk_buff *msg;
- void *hdr;
- int err;
- struct nlattr *start;
- struct add_cb_data cb;
-
- err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
- if (err)
- return err;
+ drv = cfg80211_get_dev_from_info(info);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
- if (!drv->ops->get_auth_list) {
+ if (!drv->ops->add_virtual_intf) {
err = -EOPNOTSUPP;
- goto put_drv;
- }
-
- hdr = nl80211msg_new(&msg, info->snd_pid, info->snd_seq, 0,
- NL80211_CMD_NEW_AUTH_LIST);
- if (IS_ERR(hdr)) {
- err = PTR_ERR(hdr);
- goto put_drv;
- }
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
-
- start = nla_nest_start(msg, NL80211_ATTR_BSS_LIST);
- if (!start) {
- err = -ENOBUFS;
- goto msg_free;
+ goto unlock;
}
- cb.skb = msg;
- cb.idx = 1;
rtnl_lock();
- err = drv->ops->get_auth_list(&drv->wiphy, dev, &cb, add_bssid);
+ err = drv->ops->add_virtual_intf(&drv->wiphy,
+ nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
rtnl_unlock();
- if (err)
- goto msg_free;
-
- nla_nest_end(msg, start);
- genlmsg_end(msg, hdr);
-
- err = genlmsg_unicast(msg, info->snd_pid);
- goto put_drv;
-
- nla_put_failure:
- err = -ENOBUFS;
- msg_free:
- nlmsg_free(msg);
- put_drv:
+ unlock:
cfg80211_put_dev(drv);
- dev_put(dev);
return err;
}
-static int nl80211_initiate_scan(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *drv;
- int err;
+ int ifindex, err;
struct net_device *dev;
- struct scan_params params;
- struct scan_channel *channels = NULL;
- int count = -1;
-
- if (info->attrs[NL80211_ATTR_PHYMODE])
- params.phymode = nla_get_u32(info->attrs[NL80211_ATTR_PHYMODE]);
-
- if (params.phymode > NL80211_PHYMODE_MAX)
- return -EINVAL;
err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
if (err)
return err;
-
- if (!drv->ops->initiate_scan) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- params.active = nla_get_flag(info->attrs[NL80211_ATTR_FLAG_SCAN_ACTIVE]);
-
- if (info->attrs[NL80211_ATTR_CHANNEL_LIST]) {
- struct nlattr *attr = info->attrs[NL80211_ATTR_CHANNEL_LIST];
- struct nlattr *nla;
- int rem;
- struct nlattr **tb;
-
- /* let's count first */
- count = 0;
- nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem)
- count++;
-
- if (count == 0) {
- /* assume we should actually scan all channels,
- * scanning no channels make no sense */
- count = -1;
- goto done_channels;
- }
-
- if (count > NL80211_MAX_CHANNEL_LIST_ITEM) {
- err = -EINVAL;
- goto out;
- }
-
- channels = kmalloc(count * sizeof(struct scan_channel),
- GFP_KERNEL);
- tb = kmalloc((NL80211_ATTR_MAX+1) * sizeof(struct nlattr),
- GFP_KERNEL);
-
- count = 0;
- nla_for_each_attr(nla, nla_data(attr), nla_len(attr), rem) {
- err = nla_parse(tb, NL80211_ATTR_MAX, nla_data(nla),
- nla_len(nla), nl80211_policy);
-
- if (err || !tb[NL80211_ATTR_CHANNEL]) {
- err = -EINVAL;
- kfree(tb);
- kfree(channels);
- goto out;
- }
-
- channels[count].phymode = params.phymode;
-
- if (tb[NL80211_ATTR_PHYMODE])
- channels[count].phymode =
- nla_get_u32(tb[NL80211_ATTR_PHYMODE]);
-
- if (channels[count].phymode > NL80211_PHYMODE_MAX) {
- err = -EINVAL;
- kfree(tb);
- kfree(channels);
- goto out;
- }
-
- channels[count].channel =
- nla_get_u32(tb[NL80211_ATTR_CHANNEL]);
-
- channels[count].active =
- nla_get_flag(tb[NL80211_ATTR_FLAG_SCAN_ACTIVE]);
- count++;
- }
- kfree(tb);
- }
-
- done_channels:
- params.channels = channels;
- params.n_channels = count;
-
- rtnl_lock();
- err = drv->ops->initiate_scan(&drv->wiphy, dev, &params);
- rtnl_unlock();
-
- kfree(channels);
- out:
- cfg80211_put_dev(drv);
+ ifindex = dev->ifindex;
dev_put(dev);
- return err;
-}
-
-static int nl80211_rename_wiphy(struct sk_buff *skb, struct genl_info *info)
-{
- struct cfg80211_registered_device *rdev;
- int result;
-
- if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
- return -EINVAL;
-
- rdev = cfg80211_get_dev_from_info(info);
- if (IS_ERR(rdev))
- return PTR_ERR(rdev);
-
- result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
-
- cfg80211_put_dev(rdev);
- return result;
-}
-static int nl80211_key_cmd(struct sk_buff *skb, struct genl_info *info)
-{
- struct cfg80211_registered_device *drv;
- int err, del;
- struct net_device *dev;
- struct key_params params;
- int (*act)(struct wiphy *wiphy, struct net_device *dev,
- struct key_params *params);
-
- memset(&params, 0, sizeof(params));
-
- if (!info->attrs[NL80211_ATTR_KEY_TYPE])
- return -EINVAL;
-
- if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
- return -EINVAL;
-
- params.key_type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
- if (params.key_type > NL80211_KEYTYPE_MAX)
- return -EINVAL;
-
- err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
- if (err)
- return err;
-
- switch (info->genlhdr->cmd) {
- case NL80211_CMD_ADD_KEY:
- act = drv->ops->add_key;
- del = 0;
- break;
- case NL80211_CMD_DEL_KEY:
- act = drv->ops->del_key;
- del = 1;
- break;
- default:
- act = NULL;
- }
-
- if (!act) {
+ if (!drv->ops->del_virtual_intf) {
err = -EOPNOTSUPP;
goto out;
}
- if (info->attrs[NL80211_ATTR_KEY_DATA]) {
- params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
- params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
- }
-
- if (info->attrs[NL80211_ATTR_KEY_ID]) {
- params.key_id = nla_get_u32(info->attrs[NL80211_ATTR_KEY_ID]);
- } else {
- params.key_id = -1;
- }
-
- params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
-
- if (info->attrs[NL80211_ATTR_MAC]) {
- params.macaddress = nla_data(info->attrs[NL80211_ATTR_MAC]);
- } else {
- params.macaddress = NULL;
- }
-
rtnl_lock();
- err = act(&drv->wiphy, dev, &params);
+ err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
rtnl_unlock();
out:
cfg80211_put_dev(drv);
- dev_put(dev);
return err;
}
static struct genl_ops nl80211_ops[] = {
{
- .cmd = NL80211_CMD_RENAME_WIPHY,
- .doit = nl80211_rename_wiphy,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_GET_CMDLIST,
- .doit = nl80211_get_cmdlist,
- .policy = nl80211_policy,
- /* can be retrieved by unprivileged users */
- },
- {
- .cmd = NL80211_CMD_ADD_VIRTUAL_INTERFACE,
- .doit = nl80211_add_virt_intf,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_DEL_VIRTUAL_INTERFACE,
- .doit = nl80211_del_virt_intf,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_CHANGE_VIRTUAL_INTERFACE,
- .doit = nl80211_change_virt_intf,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_GET_WIPHYS,
- .doit = nl80211_get_wiphys,
+ .cmd = NL80211_CMD_GET_WIPHY,
+ .doit = nl80211_get_wiphy,
+ .dumpit = nl80211_dump_wiphy,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
},
{
- .cmd = NL80211_CMD_GET_INTERFACES,
- .doit = nl80211_get_intfs,
- .policy = nl80211_policy,
- /* can be retrieved by unprivileged users */
- },
- {
- .cmd = NL80211_CMD_INITIATE_SCAN,
- .doit = nl80211_initiate_scan,
+ .cmd = NL80211_CMD_SET_WIPHY,
+ .doit = nl80211_set_wiphy,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
- .cmd = NL80211_CMD_GET_ASSOCIATION,
- .doit = nl80211_get_association,
+ .cmd = NL80211_CMD_GET_INTERFACE,
+ .doit = nl80211_get_interface,
+ .dumpit = nl80211_dump_interface,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
},
{
- .cmd = NL80211_CMD_ASSOCIATE,
- .doit = nl80211_associate,
+ .cmd = NL80211_CMD_SET_INTERFACE,
+ .doit = nl80211_set_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
- .cmd = NL80211_CMD_DISASSOCIATE,
- .doit = nl80211_disassoc_deauth,
+ .cmd = NL80211_CMD_NEW_INTERFACE,
+ .doit = nl80211_new_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
{
- .cmd = NL80211_CMD_DEAUTH,
- .doit = nl80211_disassoc_deauth,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_GET_AUTH_LIST,
- .doit = nl80211_get_auth_list,
- .policy = nl80211_policy,
- /* can be retrieved by unprivileged users */
- },
-/*
- {
- .cmd = NL80211_CMD_AP_SET_BEACON,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_AP_ADD_STA,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_AP_UPDATE_STA,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_AP_GET_STA_INFO,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_AP_SET_RATESETS,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
-*/
- {
- .cmd = NL80211_CMD_ADD_KEY,
- .doit = nl80211_key_cmd,
- .policy = nl80211_policy,
- .flags = GENL_ADMIN_PERM,
- },
- {
- .cmd = NL80211_CMD_DEL_KEY,
- .doit = nl80211_key_cmd,
+ .cmd = NL80211_CMD_DEL_INTERFACE,
+ .doit = nl80211_del_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
},
};
-
-/* exported functions */
-
-void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq, int flags, u8 cmd)
-{
- /* since there is no private header just add the generic one */
- return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
-}
-EXPORT_SYMBOL_GPL(nl80211hdr_put);
-
-void *nl80211msg_new(struct sk_buff **skb, u32 pid, u32 seq, int flags, u8 cmd)
-{
- void *hdr;
-
- *skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
- if (!*skb)
- return ERR_PTR(-ENOBUFS);
-
- hdr = nl80211hdr_put(*skb, pid, seq, flags, cmd);
- if (!hdr) {
- nlmsg_free(*skb);
- return ERR_PTR(-ENOBUFS);
- }
-
- return hdr;
-}
-EXPORT_SYMBOL_GPL(nl80211msg_new);
+/* multicast groups */
+static struct genl_multicast_group nl80211_config_mcgrp = {
+ .name = "config",
+};
/* notification functions */
void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
{
struct sk_buff *msg;
- void *hdr;
- hdr = nl80211msg_new(&msg, 0, 0, 0, NL80211_CMD_WIPHY_NEWNAME);
- if (IS_ERR(hdr))
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
return;
- NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
- NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&rdev->wiphy));
-
- genlmsg_end(msg, hdr);
- genlmsg_multicast(msg, 0, NL80211_GROUP_CONFIG, GFP_KERNEL);
-
- return;
+ if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
- nla_put_failure:
- nlmsg_free(msg);
+ genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
}
/* initialisation/exit functions */
@@ -982,6 +414,11 @@ int nl80211_init(void)
if (err)
goto err_out;
}
+
+ err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
+ if (err)
+ goto err_out;
+
return 0;
err_out:
genl_unregister_family(&nl80211_fam);