2 * This is the new netlink-based wireless configuration interface.
4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
8 #include <linux/module.h>
10 #include <linux/mutex.h>
11 #include <linux/list.h>
12 #include <linux/if_ether.h>
13 #include <linux/ieee80211.h>
14 #include <linux/nl80211.h>
15 #include <linux/rtnetlink.h>
16 #include <linux/netlink.h>
17 #include <net/genetlink.h>
18 #include <net/cfg80211.h>
22 /* the netlink family */
23 static struct genl_family nl80211_fam = {
24 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
25 .name = "nl80211", /* have users key off the name instead */
26 .hdrsize = 0, /* no private header */
27 .version = 1, /* no particular meaning now */
28 .maxattr = NL80211_ATTR_MAX,
31 /* internal helper: get drv and dev */
32 static int get_drv_dev_by_info_ifindex(struct genl_info *info,
33 struct cfg80211_registered_device **drv,
34 struct net_device **dev)
38 if (!info->attrs[NL80211_ATTR_IFINDEX])
41 ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
42 *dev = dev_get_by_index(&init_net, ifindex);
46 *drv = cfg80211_get_dev_from_ifindex(ifindex);
55 /* policy for the attributes */
56 static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
57 [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
58 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
59 .len = BUS_ID_SIZE-1 },
61 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
62 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
63 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
66 /* message building helper */
67 static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
70 /* since there is no private header just add the generic one */
71 return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
74 /* netlink command implementations */
76 static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
77 struct cfg80211_registered_device *dev)
81 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
85 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
86 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
87 return genlmsg_end(msg, hdr);
90 return genlmsg_cancel(msg, hdr);
93 static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
96 int start = cb->args[0];
97 struct cfg80211_registered_device *dev;
99 mutex_lock(&cfg80211_drv_mutex);
100 list_for_each_entry(dev, &cfg80211_drv_list, list) {
103 if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
104 cb->nlh->nlmsg_seq, NLM_F_MULTI,
108 mutex_unlock(&cfg80211_drv_mutex);
115 static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
118 struct cfg80211_registered_device *dev;
120 dev = cfg80211_get_dev_from_info(info);
124 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
128 if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
131 cfg80211_put_dev(dev);
133 return genlmsg_unicast(msg, info->snd_pid);
138 cfg80211_put_dev(dev);
142 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
144 struct cfg80211_registered_device *rdev;
147 if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
150 rdev = cfg80211_get_dev_from_info(info);
152 return PTR_ERR(rdev);
154 result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
156 cfg80211_put_dev(rdev);
161 static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
162 struct net_device *dev)
166 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
170 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
171 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
172 /* TODO: interface type */
173 return genlmsg_end(msg, hdr);
176 return genlmsg_cancel(msg, hdr);
179 static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
183 int wp_start = cb->args[0];
184 int if_start = cb->args[1];
185 struct cfg80211_registered_device *dev;
186 struct wireless_dev *wdev;
188 mutex_lock(&cfg80211_drv_mutex);
189 list_for_each_entry(dev, &cfg80211_drv_list, list) {
190 if (++wp_idx < wp_start)
194 mutex_lock(&dev->devlist_mtx);
195 list_for_each_entry(wdev, &dev->netdev_list, list) {
196 if (++if_idx < if_start)
198 if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
199 cb->nlh->nlmsg_seq, NLM_F_MULTI,
203 mutex_unlock(&dev->devlist_mtx);
205 mutex_unlock(&cfg80211_drv_mutex);
207 cb->args[0] = wp_idx;
208 cb->args[1] = if_idx;
213 static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
216 struct cfg80211_registered_device *dev;
217 struct net_device *netdev;
220 err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
224 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
228 if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
232 cfg80211_put_dev(dev);
234 return genlmsg_unicast(msg, info->snd_pid);
240 cfg80211_put_dev(dev);
244 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
246 struct cfg80211_registered_device *drv;
248 enum nl80211_iftype type;
249 struct net_device *dev;
251 if (info->attrs[NL80211_ATTR_IFTYPE]) {
252 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
253 if (type > NL80211_IFTYPE_MAX)
258 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
261 ifindex = dev->ifindex;
264 if (!drv->ops->change_virtual_intf) {
270 err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
274 cfg80211_put_dev(drv);
278 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
280 struct cfg80211_registered_device *drv;
282 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
284 if (!info->attrs[NL80211_ATTR_IFNAME])
287 if (info->attrs[NL80211_ATTR_IFTYPE]) {
288 type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
289 if (type > NL80211_IFTYPE_MAX)
293 drv = cfg80211_get_dev_from_info(info);
297 if (!drv->ops->add_virtual_intf) {
303 err = drv->ops->add_virtual_intf(&drv->wiphy,
304 nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
308 cfg80211_put_dev(drv);
312 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
314 struct cfg80211_registered_device *drv;
316 struct net_device *dev;
318 err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
321 ifindex = dev->ifindex;
324 if (!drv->ops->del_virtual_intf) {
330 err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
334 cfg80211_put_dev(drv);
338 static struct genl_ops nl80211_ops[] = {
340 .cmd = NL80211_CMD_GET_WIPHY,
341 .doit = nl80211_get_wiphy,
342 .dumpit = nl80211_dump_wiphy,
343 .policy = nl80211_policy,
344 /* can be retrieved by unprivileged users */
347 .cmd = NL80211_CMD_SET_WIPHY,
348 .doit = nl80211_set_wiphy,
349 .policy = nl80211_policy,
350 .flags = GENL_ADMIN_PERM,
353 .cmd = NL80211_CMD_GET_INTERFACE,
354 .doit = nl80211_get_interface,
355 .dumpit = nl80211_dump_interface,
356 .policy = nl80211_policy,
357 /* can be retrieved by unprivileged users */
360 .cmd = NL80211_CMD_SET_INTERFACE,
361 .doit = nl80211_set_interface,
362 .policy = nl80211_policy,
363 .flags = GENL_ADMIN_PERM,
366 .cmd = NL80211_CMD_NEW_INTERFACE,
367 .doit = nl80211_new_interface,
368 .policy = nl80211_policy,
369 .flags = GENL_ADMIN_PERM,
372 .cmd = NL80211_CMD_DEL_INTERFACE,
373 .doit = nl80211_del_interface,
374 .policy = nl80211_policy,
375 .flags = GENL_ADMIN_PERM,
379 /* multicast groups */
380 static struct genl_multicast_group nl80211_config_mcgrp = {
384 /* notification functions */
386 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
390 msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
394 if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
399 genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
402 /* initialisation/exit functions */
404 int nl80211_init(void)
408 err = genl_register_family(&nl80211_fam);
412 for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
413 err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
418 err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
424 genl_unregister_family(&nl80211_fam);
428 void nl80211_exit(void)
430 genl_unregister_family(&nl80211_fam);