nl80211.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * This is the new netlink-based wireless configuration interface.
  3. *
  4. * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
  5. */
  6. #include <linux/if.h>
  7. #include <linux/module.h>
  8. #include <linux/err.h>
  9. #include <linux/mutex.h>
  10. #include <linux/list.h>
  11. #include <linux/if_ether.h>
  12. #include <linux/ieee80211.h>
  13. #include <linux/nl80211.h>
  14. #include <linux/rtnetlink.h>
  15. #include <linux/netlink.h>
  16. #include <net/genetlink.h>
  17. #include <net/cfg80211.h>
  18. #include "core.h"
  19. #include "nl80211.h"
  20. /* the netlink family */
  21. static struct genl_family nl80211_fam = {
  22. .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
  23. .name = "nl80211", /* have users key off the name instead */
  24. .hdrsize = 0, /* no private header */
  25. .version = 1, /* no particular meaning now */
  26. .maxattr = NL80211_ATTR_MAX,
  27. };
  28. /* internal helper: get drv and dev */
  29. static int get_drv_dev_by_info_ifindex(struct genl_info *info,
  30. struct cfg80211_registered_device **drv,
  31. struct net_device **dev)
  32. {
  33. int ifindex;
  34. if (!info->attrs[NL80211_ATTR_IFINDEX])
  35. return -EINVAL;
  36. ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
  37. *dev = dev_get_by_index(&init_net, ifindex);
  38. if (!*dev)
  39. return -ENODEV;
  40. *drv = cfg80211_get_dev_from_ifindex(ifindex);
  41. if (IS_ERR(*drv)) {
  42. dev_put(*dev);
  43. return PTR_ERR(*drv);
  44. }
  45. return 0;
  46. }
  47. /* policy for the attributes */
  48. static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
  49. [NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
  50. [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
  51. .len = BUS_ID_SIZE-1 },
  52. [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
  53. [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
  54. [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
  55. };
  56. /* message building helper */
  57. static inline void *nl80211hdr_put(struct sk_buff *skb, u32 pid, u32 seq,
  58. int flags, u8 cmd)
  59. {
  60. /* since there is no private header just add the generic one */
  61. return genlmsg_put(skb, pid, seq, &nl80211_fam, flags, cmd);
  62. }
  63. /* netlink command implementations */
  64. static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
  65. struct cfg80211_registered_device *dev)
  66. {
  67. void *hdr;
  68. hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
  69. if (!hdr)
  70. return -1;
  71. NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
  72. NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
  73. return genlmsg_end(msg, hdr);
  74. nla_put_failure:
  75. return genlmsg_cancel(msg, hdr);
  76. }
  77. static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
  78. {
  79. int idx = 0;
  80. int start = cb->args[0];
  81. struct cfg80211_registered_device *dev;
  82. mutex_lock(&cfg80211_drv_mutex);
  83. list_for_each_entry(dev, &cfg80211_drv_list, list) {
  84. if (++idx < start)
  85. continue;
  86. if (nl80211_send_wiphy(skb, NETLINK_CB(cb->skb).pid,
  87. cb->nlh->nlmsg_seq, NLM_F_MULTI,
  88. dev) < 0)
  89. break;
  90. }
  91. mutex_unlock(&cfg80211_drv_mutex);
  92. cb->args[0] = idx;
  93. return skb->len;
  94. }
  95. static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info)
  96. {
  97. struct sk_buff *msg;
  98. struct cfg80211_registered_device *dev;
  99. dev = cfg80211_get_dev_from_info(info);
  100. if (IS_ERR(dev))
  101. return PTR_ERR(dev);
  102. msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  103. if (!msg)
  104. goto out_err;
  105. if (nl80211_send_wiphy(msg, info->snd_pid, info->snd_seq, 0, dev) < 0)
  106. goto out_free;
  107. cfg80211_put_dev(dev);
  108. return genlmsg_unicast(msg, info->snd_pid);
  109. out_free:
  110. nlmsg_free(msg);
  111. out_err:
  112. cfg80211_put_dev(dev);
  113. return -ENOBUFS;
  114. }
  115. static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
  116. {
  117. struct cfg80211_registered_device *rdev;
  118. int result;
  119. if (!info->attrs[NL80211_ATTR_WIPHY_NAME])
  120. return -EINVAL;
  121. rdev = cfg80211_get_dev_from_info(info);
  122. if (IS_ERR(rdev))
  123. return PTR_ERR(rdev);
  124. result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME]));
  125. cfg80211_put_dev(rdev);
  126. return result;
  127. }
  128. static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
  129. struct net_device *dev)
  130. {
  131. void *hdr;
  132. hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
  133. if (!hdr)
  134. return -1;
  135. NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
  136. NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, dev->name);
  137. /* TODO: interface type */
  138. return genlmsg_end(msg, hdr);
  139. nla_put_failure:
  140. return genlmsg_cancel(msg, hdr);
  141. }
  142. static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
  143. {
  144. int wp_idx = 0;
  145. int if_idx = 0;
  146. int wp_start = cb->args[0];
  147. int if_start = cb->args[1];
  148. struct cfg80211_registered_device *dev;
  149. struct wireless_dev *wdev;
  150. mutex_lock(&cfg80211_drv_mutex);
  151. list_for_each_entry(dev, &cfg80211_drv_list, list) {
  152. if (++wp_idx < wp_start)
  153. continue;
  154. if_idx = 0;
  155. mutex_lock(&dev->devlist_mtx);
  156. list_for_each_entry(wdev, &dev->netdev_list, list) {
  157. if (++if_idx < if_start)
  158. continue;
  159. if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
  160. cb->nlh->nlmsg_seq, NLM_F_MULTI,
  161. wdev->netdev) < 0)
  162. break;
  163. }
  164. mutex_unlock(&dev->devlist_mtx);
  165. }
  166. mutex_unlock(&cfg80211_drv_mutex);
  167. cb->args[0] = wp_idx;
  168. cb->args[1] = if_idx;
  169. return skb->len;
  170. }
  171. static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
  172. {
  173. struct sk_buff *msg;
  174. struct cfg80211_registered_device *dev;
  175. struct net_device *netdev;
  176. int err;
  177. err = get_drv_dev_by_info_ifindex(info, &dev, &netdev);
  178. if (err)
  179. return err;
  180. msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  181. if (!msg)
  182. goto out_err;
  183. if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, netdev) < 0)
  184. goto out_free;
  185. dev_put(netdev);
  186. cfg80211_put_dev(dev);
  187. return genlmsg_unicast(msg, info->snd_pid);
  188. out_free:
  189. nlmsg_free(msg);
  190. out_err:
  191. dev_put(netdev);
  192. cfg80211_put_dev(dev);
  193. return -ENOBUFS;
  194. }
  195. static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
  196. {
  197. struct cfg80211_registered_device *drv;
  198. int err, ifindex;
  199. enum nl80211_iftype type;
  200. struct net_device *dev;
  201. if (info->attrs[NL80211_ATTR_IFTYPE]) {
  202. type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
  203. if (type > NL80211_IFTYPE_MAX)
  204. return -EINVAL;
  205. } else
  206. return -EINVAL;
  207. err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
  208. if (err)
  209. return err;
  210. ifindex = dev->ifindex;
  211. dev_put(dev);
  212. if (!drv->ops->change_virtual_intf) {
  213. err = -EOPNOTSUPP;
  214. goto unlock;
  215. }
  216. rtnl_lock();
  217. err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
  218. rtnl_unlock();
  219. unlock:
  220. cfg80211_put_dev(drv);
  221. return err;
  222. }
  223. static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
  224. {
  225. struct cfg80211_registered_device *drv;
  226. int err;
  227. enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
  228. if (!info->attrs[NL80211_ATTR_IFNAME])
  229. return -EINVAL;
  230. if (info->attrs[NL80211_ATTR_IFTYPE]) {
  231. type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
  232. if (type > NL80211_IFTYPE_MAX)
  233. return -EINVAL;
  234. }
  235. drv = cfg80211_get_dev_from_info(info);
  236. if (IS_ERR(drv))
  237. return PTR_ERR(drv);
  238. if (!drv->ops->add_virtual_intf) {
  239. err = -EOPNOTSUPP;
  240. goto unlock;
  241. }
  242. rtnl_lock();
  243. err = drv->ops->add_virtual_intf(&drv->wiphy,
  244. nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
  245. rtnl_unlock();
  246. unlock:
  247. cfg80211_put_dev(drv);
  248. return err;
  249. }
  250. static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
  251. {
  252. struct cfg80211_registered_device *drv;
  253. int ifindex, err;
  254. struct net_device *dev;
  255. err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
  256. if (err)
  257. return err;
  258. ifindex = dev->ifindex;
  259. dev_put(dev);
  260. if (!drv->ops->del_virtual_intf) {
  261. err = -EOPNOTSUPP;
  262. goto out;
  263. }
  264. rtnl_lock();
  265. err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex);
  266. rtnl_unlock();
  267. out:
  268. cfg80211_put_dev(drv);
  269. return err;
  270. }
  271. static struct genl_ops nl80211_ops[] = {
  272. {
  273. .cmd = NL80211_CMD_GET_WIPHY,
  274. .doit = nl80211_get_wiphy,
  275. .dumpit = nl80211_dump_wiphy,
  276. .policy = nl80211_policy,
  277. /* can be retrieved by unprivileged users */
  278. },
  279. {
  280. .cmd = NL80211_CMD_SET_WIPHY,
  281. .doit = nl80211_set_wiphy,
  282. .policy = nl80211_policy,
  283. .flags = GENL_ADMIN_PERM,
  284. },
  285. {
  286. .cmd = NL80211_CMD_GET_INTERFACE,
  287. .doit = nl80211_get_interface,
  288. .dumpit = nl80211_dump_interface,
  289. .policy = nl80211_policy,
  290. /* can be retrieved by unprivileged users */
  291. },
  292. {
  293. .cmd = NL80211_CMD_SET_INTERFACE,
  294. .doit = nl80211_set_interface,
  295. .policy = nl80211_policy,
  296. .flags = GENL_ADMIN_PERM,
  297. },
  298. {
  299. .cmd = NL80211_CMD_NEW_INTERFACE,
  300. .doit = nl80211_new_interface,
  301. .policy = nl80211_policy,
  302. .flags = GENL_ADMIN_PERM,
  303. },
  304. {
  305. .cmd = NL80211_CMD_DEL_INTERFACE,
  306. .doit = nl80211_del_interface,
  307. .policy = nl80211_policy,
  308. .flags = GENL_ADMIN_PERM,
  309. },
  310. };
  311. /* multicast groups */
  312. static struct genl_multicast_group nl80211_config_mcgrp = {
  313. .name = "config",
  314. };
  315. /* notification functions */
  316. void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
  317. {
  318. struct sk_buff *msg;
  319. msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  320. if (!msg)
  321. return;
  322. if (nl80211_send_wiphy(msg, 0, 0, 0, rdev) < 0) {
  323. nlmsg_free(msg);
  324. return;
  325. }
  326. genlmsg_multicast(msg, 0, nl80211_config_mcgrp.id, GFP_KERNEL);
  327. }
  328. /* initialisation/exit functions */
  329. int nl80211_init(void)
  330. {
  331. int err, i;
  332. err = genl_register_family(&nl80211_fam);
  333. if (err)
  334. return err;
  335. for (i = 0; i < ARRAY_SIZE(nl80211_ops); i++) {
  336. err = genl_register_ops(&nl80211_fam, &nl80211_ops[i]);
  337. if (err)
  338. goto err_out;
  339. }
  340. err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
  341. if (err)
  342. goto err_out;
  343. return 0;
  344. err_out:
  345. genl_unregister_family(&nl80211_fam);
  346. return err;
  347. }
  348. void nl80211_exit(void)
  349. {
  350. genl_unregister_family(&nl80211_fam);
  351. }