nl802154.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  1. /* This program is free software; you can redistribute it and/or modify
  2. * it under the terms of the GNU General Public License version 2
  3. * as published by the Free Software Foundation.
  4. *
  5. * This program is distributed in the hope that it will be useful,
  6. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. * GNU General Public License for more details.
  9. *
  10. * Authors:
  11. * Alexander Aring <aar@pengutronix.de>
  12. *
  13. * Based on: net/wireless/nl80211.c
  14. */
  15. #include <linux/rtnetlink.h>
  16. #include <net/cfg802154.h>
  17. #include <net/genetlink.h>
  18. #include <net/mac802154.h>
  19. #include <net/netlink.h>
  20. #include <net/nl802154.h>
  21. #include <net/sock.h>
  22. #include "nl802154.h"
  23. #include "rdev-ops.h"
  24. #include "core.h"
  25. static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
  26. struct genl_info *info);
  27. static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
  28. struct genl_info *info);
  29. /* the netlink family */
  30. static struct genl_family nl802154_fam = {
  31. .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
  32. .name = NL802154_GENL_NAME, /* have users key off the name instead */
  33. .hdrsize = 0, /* no private header */
  34. .version = 1, /* no particular meaning now */
  35. .maxattr = NL802154_ATTR_MAX,
  36. .netnsok = true,
  37. .pre_doit = nl802154_pre_doit,
  38. .post_doit = nl802154_post_doit,
  39. };
  40. /* multicast groups */
  41. enum nl802154_multicast_groups {
  42. NL802154_MCGRP_CONFIG,
  43. };
  44. static const struct genl_multicast_group nl802154_mcgrps[] = {
  45. [NL802154_MCGRP_CONFIG] = { .name = "config", },
  46. };
  47. /* returns ERR_PTR values */
  48. static struct wpan_dev *
  49. __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs)
  50. {
  51. struct cfg802154_registered_device *rdev;
  52. struct wpan_dev *result = NULL;
  53. bool have_ifidx = attrs[NL802154_ATTR_IFINDEX];
  54. bool have_wpan_dev_id = attrs[NL802154_ATTR_WPAN_DEV];
  55. u64 wpan_dev_id;
  56. int wpan_phy_idx = -1;
  57. int ifidx = -1;
  58. ASSERT_RTNL();
  59. if (!have_ifidx && !have_wpan_dev_id)
  60. return ERR_PTR(-EINVAL);
  61. if (have_ifidx)
  62. ifidx = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
  63. if (have_wpan_dev_id) {
  64. wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
  65. wpan_phy_idx = wpan_dev_id >> 32;
  66. }
  67. list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
  68. struct wpan_dev *wpan_dev;
  69. /* TODO netns compare */
  70. if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx)
  71. continue;
  72. list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
  73. if (have_ifidx && wpan_dev->netdev &&
  74. wpan_dev->netdev->ifindex == ifidx) {
  75. result = wpan_dev;
  76. break;
  77. }
  78. if (have_wpan_dev_id &&
  79. wpan_dev->identifier == (u32)wpan_dev_id) {
  80. result = wpan_dev;
  81. break;
  82. }
  83. }
  84. if (result)
  85. break;
  86. }
  87. if (result)
  88. return result;
  89. return ERR_PTR(-ENODEV);
  90. }
  91. static struct cfg802154_registered_device *
  92. __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
  93. {
  94. struct cfg802154_registered_device *rdev = NULL, *tmp;
  95. struct net_device *netdev;
  96. ASSERT_RTNL();
  97. if (!attrs[NL802154_ATTR_WPAN_PHY] &&
  98. !attrs[NL802154_ATTR_IFINDEX] &&
  99. !attrs[NL802154_ATTR_WPAN_DEV])
  100. return ERR_PTR(-EINVAL);
  101. if (attrs[NL802154_ATTR_WPAN_PHY])
  102. rdev = cfg802154_rdev_by_wpan_phy_idx(
  103. nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY]));
  104. if (attrs[NL802154_ATTR_WPAN_DEV]) {
  105. u64 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
  106. struct wpan_dev *wpan_dev;
  107. bool found = false;
  108. tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32);
  109. if (tmp) {
  110. /* make sure wpan_dev exists */
  111. list_for_each_entry(wpan_dev, &tmp->wpan_dev_list, list) {
  112. if (wpan_dev->identifier != (u32)wpan_dev_id)
  113. continue;
  114. found = true;
  115. break;
  116. }
  117. if (!found)
  118. tmp = NULL;
  119. if (rdev && tmp != rdev)
  120. return ERR_PTR(-EINVAL);
  121. rdev = tmp;
  122. }
  123. }
  124. if (attrs[NL802154_ATTR_IFINDEX]) {
  125. int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
  126. netdev = __dev_get_by_index(netns, ifindex);
  127. if (netdev) {
  128. if (netdev->ieee802154_ptr)
  129. tmp = wpan_phy_to_rdev(
  130. netdev->ieee802154_ptr->wpan_phy);
  131. else
  132. tmp = NULL;
  133. /* not wireless device -- return error */
  134. if (!tmp)
  135. return ERR_PTR(-EINVAL);
  136. /* mismatch -- return error */
  137. if (rdev && tmp != rdev)
  138. return ERR_PTR(-EINVAL);
  139. rdev = tmp;
  140. }
  141. }
  142. if (!rdev)
  143. return ERR_PTR(-ENODEV);
  144. /* TODO netns compare */
  145. return rdev;
  146. }
  147. /* This function returns a pointer to the driver
  148. * that the genl_info item that is passed refers to.
  149. *
  150. * The result of this can be a PTR_ERR and hence must
  151. * be checked with IS_ERR() for errors.
  152. */
  153. static struct cfg802154_registered_device *
  154. cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info)
  155. {
  156. return __cfg802154_rdev_from_attrs(netns, info->attrs);
  157. }
  158. /* policy for the attributes */
  159. static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
  160. [NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 },
  161. [NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING,
  162. .len = 20-1 },
  163. [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 },
  164. [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 },
  165. [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
  166. [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 },
  167. [NL802154_ATTR_PAGE] = { .type = NLA_U8, },
  168. [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, },
  169. [NL802154_ATTR_TX_POWER] = { .type = NLA_S32, },
  170. [NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, },
  171. [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, },
  172. [NL802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
  173. [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
  174. [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, },
  175. [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
  176. [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
  177. [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, },
  178. [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, },
  179. [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, },
  180. [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
  181. [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
  182. [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
  183. [NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED },
  184. [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },
  185. };
  186. /* message building helper */
  187. static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
  188. int flags, u8 cmd)
  189. {
  190. /* since there is no private header just add the generic one */
  191. return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
  192. }
  193. static int
  194. nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
  195. {
  196. struct nlattr *nl_flags = nla_nest_start(msg, attr);
  197. int i;
  198. if (!nl_flags)
  199. return -ENOBUFS;
  200. i = 0;
  201. while (mask) {
  202. if ((mask & 1) && nla_put_flag(msg, i))
  203. return -ENOBUFS;
  204. mask >>= 1;
  205. i++;
  206. }
  207. nla_nest_end(msg, nl_flags);
  208. return 0;
  209. }
  210. static int
  211. nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
  212. struct sk_buff *msg)
  213. {
  214. struct nlattr *nl_page;
  215. unsigned long page;
  216. nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
  217. if (!nl_page)
  218. return -ENOBUFS;
  219. for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
  220. if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
  221. rdev->wpan_phy.supported.channels[page]))
  222. return -ENOBUFS;
  223. }
  224. nla_nest_end(msg, nl_page);
  225. return 0;
  226. }
  227. static int
  228. nl802154_put_capabilities(struct sk_buff *msg,
  229. struct cfg802154_registered_device *rdev)
  230. {
  231. const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
  232. struct nlattr *nl_caps, *nl_channels;
  233. int i;
  234. nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
  235. if (!nl_caps)
  236. return -ENOBUFS;
  237. nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
  238. if (!nl_channels)
  239. return -ENOBUFS;
  240. for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
  241. if (caps->channels[i]) {
  242. if (nl802154_put_flags(msg, i, caps->channels[i]))
  243. return -ENOBUFS;
  244. }
  245. }
  246. nla_nest_end(msg, nl_channels);
  247. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
  248. struct nlattr *nl_ed_lvls;
  249. nl_ed_lvls = nla_nest_start(msg,
  250. NL802154_CAP_ATTR_CCA_ED_LEVELS);
  251. if (!nl_ed_lvls)
  252. return -ENOBUFS;
  253. for (i = 0; i < caps->cca_ed_levels_size; i++) {
  254. if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
  255. return -ENOBUFS;
  256. }
  257. nla_nest_end(msg, nl_ed_lvls);
  258. }
  259. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
  260. struct nlattr *nl_tx_pwrs;
  261. nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
  262. if (!nl_tx_pwrs)
  263. return -ENOBUFS;
  264. for (i = 0; i < caps->tx_powers_size; i++) {
  265. if (nla_put_s32(msg, i, caps->tx_powers[i]))
  266. return -ENOBUFS;
  267. }
  268. nla_nest_end(msg, nl_tx_pwrs);
  269. }
  270. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
  271. if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
  272. caps->cca_modes) ||
  273. nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
  274. caps->cca_opts))
  275. return -ENOBUFS;
  276. }
  277. if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
  278. nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
  279. nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
  280. nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
  281. nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
  282. caps->min_csma_backoffs) ||
  283. nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
  284. caps->max_csma_backoffs) ||
  285. nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
  286. caps->min_frame_retries) ||
  287. nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
  288. caps->max_frame_retries) ||
  289. nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
  290. caps->iftypes) ||
  291. nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
  292. return -ENOBUFS;
  293. nla_nest_end(msg, nl_caps);
  294. return 0;
  295. }
  296. static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
  297. enum nl802154_commands cmd,
  298. struct sk_buff *msg, u32 portid, u32 seq,
  299. int flags)
  300. {
  301. struct nlattr *nl_cmds;
  302. void *hdr;
  303. int i;
  304. hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
  305. if (!hdr)
  306. return -ENOBUFS;
  307. if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
  308. nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
  309. wpan_phy_name(&rdev->wpan_phy)) ||
  310. nla_put_u32(msg, NL802154_ATTR_GENERATION,
  311. cfg802154_rdev_list_generation))
  312. goto nla_put_failure;
  313. if (cmd != NL802154_CMD_NEW_WPAN_PHY)
  314. goto finish;
  315. /* DUMP PHY PIB */
  316. /* current channel settings */
  317. if (nla_put_u8(msg, NL802154_ATTR_PAGE,
  318. rdev->wpan_phy.current_page) ||
  319. nla_put_u8(msg, NL802154_ATTR_CHANNEL,
  320. rdev->wpan_phy.current_channel))
  321. goto nla_put_failure;
  322. /* TODO remove this behaviour, we still keep support it for a while
  323. * so users can change the behaviour to the new one.
  324. */
  325. if (nl802154_send_wpan_phy_channels(rdev, msg))
  326. goto nla_put_failure;
  327. /* cca mode */
  328. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
  329. if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
  330. rdev->wpan_phy.cca.mode))
  331. goto nla_put_failure;
  332. if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
  333. if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
  334. rdev->wpan_phy.cca.opt))
  335. goto nla_put_failure;
  336. }
  337. }
  338. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
  339. if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
  340. rdev->wpan_phy.transmit_power))
  341. goto nla_put_failure;
  342. }
  343. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
  344. if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
  345. rdev->wpan_phy.cca_ed_level))
  346. goto nla_put_failure;
  347. }
  348. if (nl802154_put_capabilities(msg, rdev))
  349. goto nla_put_failure;
  350. nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
  351. if (!nl_cmds)
  352. goto nla_put_failure;
  353. i = 0;
  354. #define CMD(op, n) \
  355. do { \
  356. if (rdev->ops->op) { \
  357. i++; \
  358. if (nla_put_u32(msg, i, NL802154_CMD_ ## n)) \
  359. goto nla_put_failure; \
  360. } \
  361. } while (0)
  362. CMD(add_virtual_intf, NEW_INTERFACE);
  363. CMD(del_virtual_intf, DEL_INTERFACE);
  364. CMD(set_channel, SET_CHANNEL);
  365. CMD(set_pan_id, SET_PAN_ID);
  366. CMD(set_short_addr, SET_SHORT_ADDR);
  367. CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
  368. CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
  369. CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
  370. CMD(set_lbt_mode, SET_LBT_MODE);
  371. CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
  372. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
  373. CMD(set_tx_power, SET_TX_POWER);
  374. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
  375. CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
  376. if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
  377. CMD(set_cca_mode, SET_CCA_MODE);
  378. #undef CMD
  379. nla_nest_end(msg, nl_cmds);
  380. finish:
  381. genlmsg_end(msg, hdr);
  382. return 0;
  383. nla_put_failure:
  384. genlmsg_cancel(msg, hdr);
  385. return -EMSGSIZE;
  386. }
  387. struct nl802154_dump_wpan_phy_state {
  388. s64 filter_wpan_phy;
  389. long start;
  390. };
  391. static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
  392. struct netlink_callback *cb,
  393. struct nl802154_dump_wpan_phy_state *state)
  394. {
  395. struct nlattr **tb = nl802154_fam.attrbuf;
  396. int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
  397. tb, nl802154_fam.maxattr, nl802154_policy);
  398. /* TODO check if we can handle error here,
  399. * we have no backward compatibility
  400. */
  401. if (ret)
  402. return 0;
  403. if (tb[NL802154_ATTR_WPAN_PHY])
  404. state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
  405. if (tb[NL802154_ATTR_WPAN_DEV])
  406. state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
  407. if (tb[NL802154_ATTR_IFINDEX]) {
  408. struct net_device *netdev;
  409. struct cfg802154_registered_device *rdev;
  410. int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
  411. /* TODO netns */
  412. netdev = __dev_get_by_index(&init_net, ifidx);
  413. if (!netdev)
  414. return -ENODEV;
  415. if (netdev->ieee802154_ptr) {
  416. rdev = wpan_phy_to_rdev(
  417. netdev->ieee802154_ptr->wpan_phy);
  418. state->filter_wpan_phy = rdev->wpan_phy_idx;
  419. }
  420. }
  421. return 0;
  422. }
  423. static int
  424. nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
  425. {
  426. int idx = 0, ret;
  427. struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
  428. struct cfg802154_registered_device *rdev;
  429. rtnl_lock();
  430. if (!state) {
  431. state = kzalloc(sizeof(*state), GFP_KERNEL);
  432. if (!state) {
  433. rtnl_unlock();
  434. return -ENOMEM;
  435. }
  436. state->filter_wpan_phy = -1;
  437. ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
  438. if (ret) {
  439. kfree(state);
  440. rtnl_unlock();
  441. return ret;
  442. }
  443. cb->args[0] = (long)state;
  444. }
  445. list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
  446. /* TODO net ns compare */
  447. if (++idx <= state->start)
  448. continue;
  449. if (state->filter_wpan_phy != -1 &&
  450. state->filter_wpan_phy != rdev->wpan_phy_idx)
  451. continue;
  452. /* attempt to fit multiple wpan_phy data chunks into the skb */
  453. ret = nl802154_send_wpan_phy(rdev,
  454. NL802154_CMD_NEW_WPAN_PHY,
  455. skb,
  456. NETLINK_CB(cb->skb).portid,
  457. cb->nlh->nlmsg_seq, NLM_F_MULTI);
  458. if (ret < 0) {
  459. if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
  460. !skb->len && cb->min_dump_alloc < 4096) {
  461. cb->min_dump_alloc = 4096;
  462. rtnl_unlock();
  463. return 1;
  464. }
  465. idx--;
  466. break;
  467. }
  468. break;
  469. }
  470. rtnl_unlock();
  471. state->start = idx;
  472. return skb->len;
  473. }
  474. static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
  475. {
  476. kfree((void *)cb->args[0]);
  477. return 0;
  478. }
  479. static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
  480. {
  481. struct sk_buff *msg;
  482. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  483. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  484. if (!msg)
  485. return -ENOMEM;
  486. if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
  487. info->snd_portid, info->snd_seq, 0) < 0) {
  488. nlmsg_free(msg);
  489. return -ENOBUFS;
  490. }
  491. return genlmsg_reply(msg, info);
  492. }
  493. static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
  494. {
  495. return (u64)wpan_dev->identifier |
  496. ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
  497. }
  498. static int
  499. nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
  500. struct cfg802154_registered_device *rdev,
  501. struct wpan_dev *wpan_dev)
  502. {
  503. struct net_device *dev = wpan_dev->netdev;
  504. void *hdr;
  505. hdr = nl802154hdr_put(msg, portid, seq, flags,
  506. NL802154_CMD_NEW_INTERFACE);
  507. if (!hdr)
  508. return -1;
  509. if (dev &&
  510. (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
  511. nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
  512. goto nla_put_failure;
  513. if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
  514. nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
  515. nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
  516. nla_put_u32(msg, NL802154_ATTR_GENERATION,
  517. rdev->devlist_generation ^
  518. (cfg802154_rdev_list_generation << 2)))
  519. goto nla_put_failure;
  520. /* address settings */
  521. if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
  522. wpan_dev->extended_addr) ||
  523. nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
  524. wpan_dev->short_addr) ||
  525. nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
  526. goto nla_put_failure;
  527. /* ARET handling */
  528. if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
  529. wpan_dev->frame_retries) ||
  530. nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
  531. nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
  532. wpan_dev->csma_retries) ||
  533. nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
  534. goto nla_put_failure;
  535. /* listen before transmit */
  536. if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
  537. goto nla_put_failure;
  538. /* ackreq default behaviour */
  539. if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
  540. goto nla_put_failure;
  541. genlmsg_end(msg, hdr);
  542. return 0;
  543. nla_put_failure:
  544. genlmsg_cancel(msg, hdr);
  545. return -EMSGSIZE;
  546. }
  547. static int
  548. nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
  549. {
  550. int wp_idx = 0;
  551. int if_idx = 0;
  552. int wp_start = cb->args[0];
  553. int if_start = cb->args[1];
  554. struct cfg802154_registered_device *rdev;
  555. struct wpan_dev *wpan_dev;
  556. rtnl_lock();
  557. list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
  558. /* TODO netns compare */
  559. if (wp_idx < wp_start) {
  560. wp_idx++;
  561. continue;
  562. }
  563. if_idx = 0;
  564. list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
  565. if (if_idx < if_start) {
  566. if_idx++;
  567. continue;
  568. }
  569. if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
  570. cb->nlh->nlmsg_seq, NLM_F_MULTI,
  571. rdev, wpan_dev) < 0) {
  572. goto out;
  573. }
  574. if_idx++;
  575. }
  576. wp_idx++;
  577. }
  578. out:
  579. rtnl_unlock();
  580. cb->args[0] = wp_idx;
  581. cb->args[1] = if_idx;
  582. return skb->len;
  583. }
  584. static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
  585. {
  586. struct sk_buff *msg;
  587. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  588. struct wpan_dev *wdev = info->user_ptr[1];
  589. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  590. if (!msg)
  591. return -ENOMEM;
  592. if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
  593. rdev, wdev) < 0) {
  594. nlmsg_free(msg);
  595. return -ENOBUFS;
  596. }
  597. return genlmsg_reply(msg, info);
  598. }
  599. static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
  600. {
  601. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  602. enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
  603. __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
  604. /* TODO avoid failing a new interface
  605. * creation due to pending removal?
  606. */
  607. if (!info->attrs[NL802154_ATTR_IFNAME])
  608. return -EINVAL;
  609. if (info->attrs[NL802154_ATTR_IFTYPE]) {
  610. type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
  611. if (type > NL802154_IFTYPE_MAX ||
  612. !(rdev->wpan_phy.supported.iftypes & BIT(type)))
  613. return -EINVAL;
  614. }
  615. /* TODO add nla_get_le64 to netlink */
  616. if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
  617. extended_addr = (__force __le64)nla_get_u64(
  618. info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
  619. if (!rdev->ops->add_virtual_intf)
  620. return -EOPNOTSUPP;
  621. return rdev_add_virtual_intf(rdev,
  622. nla_data(info->attrs[NL802154_ATTR_IFNAME]),
  623. NET_NAME_USER, type, extended_addr);
  624. }
  625. static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
  626. {
  627. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  628. struct wpan_dev *wpan_dev = info->user_ptr[1];
  629. if (!rdev->ops->del_virtual_intf)
  630. return -EOPNOTSUPP;
  631. /* If we remove a wpan device without a netdev then clear
  632. * user_ptr[1] so that nl802154_post_doit won't dereference it
  633. * to check if it needs to do dev_put(). Otherwise it crashes
  634. * since the wpan_dev has been freed, unlike with a netdev where
  635. * we need the dev_put() for the netdev to really be freed.
  636. */
  637. if (!wpan_dev->netdev)
  638. info->user_ptr[1] = NULL;
  639. return rdev_del_virtual_intf(rdev, wpan_dev);
  640. }
  641. static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
  642. {
  643. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  644. u8 channel, page;
  645. if (!info->attrs[NL802154_ATTR_PAGE] ||
  646. !info->attrs[NL802154_ATTR_CHANNEL])
  647. return -EINVAL;
  648. page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
  649. channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
  650. /* check 802.15.4 constraints */
  651. if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
  652. !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
  653. return -EINVAL;
  654. return rdev_set_channel(rdev, page, channel);
  655. }
  656. static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
  657. {
  658. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  659. struct wpan_phy_cca cca;
  660. if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
  661. return -EOPNOTSUPP;
  662. if (!info->attrs[NL802154_ATTR_CCA_MODE])
  663. return -EINVAL;
  664. cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
  665. /* checking 802.15.4 constraints */
  666. if (cca.mode < NL802154_CCA_ENERGY ||
  667. cca.mode > NL802154_CCA_ATTR_MAX ||
  668. !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
  669. return -EINVAL;
  670. if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
  671. if (!info->attrs[NL802154_ATTR_CCA_OPT])
  672. return -EINVAL;
  673. cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
  674. if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
  675. !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
  676. return -EINVAL;
  677. }
  678. return rdev_set_cca_mode(rdev, &cca);
  679. }
  680. static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
  681. {
  682. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  683. s32 ed_level;
  684. int i;
  685. if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
  686. return -EOPNOTSUPP;
  687. if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
  688. return -EINVAL;
  689. ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
  690. for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
  691. if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
  692. return rdev_set_cca_ed_level(rdev, ed_level);
  693. }
  694. return -EINVAL;
  695. }
  696. static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
  697. {
  698. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  699. s32 power;
  700. int i;
  701. if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
  702. return -EOPNOTSUPP;
  703. if (!info->attrs[NL802154_ATTR_TX_POWER])
  704. return -EINVAL;
  705. power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
  706. for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
  707. if (power == rdev->wpan_phy.supported.tx_powers[i])
  708. return rdev_set_tx_power(rdev, power);
  709. }
  710. return -EINVAL;
  711. }
  712. static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
  713. {
  714. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  715. struct net_device *dev = info->user_ptr[1];
  716. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  717. __le16 pan_id;
  718. /* conflict here while tx/rx calls */
  719. if (netif_running(dev))
  720. return -EBUSY;
  721. /* don't change address fields on monitor */
  722. if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
  723. !info->attrs[NL802154_ATTR_PAN_ID])
  724. return -EINVAL;
  725. pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
  726. /* TODO
  727. * I am not sure about to check here on broadcast pan_id.
  728. * Broadcast is a valid setting, comment from 802.15.4:
  729. * If this value is 0xffff, the device is not associated.
  730. *
  731. * This could useful to simple deassociate an device.
  732. */
  733. if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
  734. return -EINVAL;
  735. return rdev_set_pan_id(rdev, wpan_dev, pan_id);
  736. }
  737. static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
  738. {
  739. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  740. struct net_device *dev = info->user_ptr[1];
  741. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  742. __le16 short_addr;
  743. /* conflict here while tx/rx calls */
  744. if (netif_running(dev))
  745. return -EBUSY;
  746. /* don't change address fields on monitor */
  747. if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
  748. !info->attrs[NL802154_ATTR_SHORT_ADDR])
  749. return -EINVAL;
  750. short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
  751. /* TODO
  752. * I am not sure about to check here on broadcast short_addr.
  753. * Broadcast is a valid setting, comment from 802.15.4:
  754. * A value of 0xfffe indicates that the device has
  755. * associated but has not been allocated an address. A
  756. * value of 0xffff indicates that the device does not
  757. * have a short address.
  758. *
  759. * I think we should allow to set these settings but
  760. * don't allow to allow socket communication with it.
  761. */
  762. if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
  763. short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
  764. return -EINVAL;
  765. return rdev_set_short_addr(rdev, wpan_dev, short_addr);
  766. }
  767. static int
  768. nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
  769. {
  770. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  771. struct net_device *dev = info->user_ptr[1];
  772. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  773. u8 min_be, max_be;
  774. /* should be set on netif open inside phy settings */
  775. if (netif_running(dev))
  776. return -EBUSY;
  777. if (!info->attrs[NL802154_ATTR_MIN_BE] ||
  778. !info->attrs[NL802154_ATTR_MAX_BE])
  779. return -EINVAL;
  780. min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
  781. max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
  782. /* check 802.15.4 constraints */
  783. if (min_be < rdev->wpan_phy.supported.min_minbe ||
  784. min_be > rdev->wpan_phy.supported.max_minbe ||
  785. max_be < rdev->wpan_phy.supported.min_maxbe ||
  786. max_be > rdev->wpan_phy.supported.max_maxbe ||
  787. min_be > max_be)
  788. return -EINVAL;
  789. return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
  790. }
  791. static int
  792. nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
  793. {
  794. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  795. struct net_device *dev = info->user_ptr[1];
  796. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  797. u8 max_csma_backoffs;
  798. /* conflict here while other running iface settings */
  799. if (netif_running(dev))
  800. return -EBUSY;
  801. if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
  802. return -EINVAL;
  803. max_csma_backoffs = nla_get_u8(
  804. info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
  805. /* check 802.15.4 constraints */
  806. if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
  807. max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
  808. return -EINVAL;
  809. return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
  810. }
  811. static int
  812. nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
  813. {
  814. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  815. struct net_device *dev = info->user_ptr[1];
  816. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  817. s8 max_frame_retries;
  818. if (netif_running(dev))
  819. return -EBUSY;
  820. if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
  821. return -EINVAL;
  822. max_frame_retries = nla_get_s8(
  823. info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
  824. /* check 802.15.4 constraints */
  825. if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
  826. max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
  827. return -EINVAL;
  828. return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
  829. }
  830. static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
  831. {
  832. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  833. struct net_device *dev = info->user_ptr[1];
  834. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  835. int mode;
  836. if (netif_running(dev))
  837. return -EBUSY;
  838. if (!info->attrs[NL802154_ATTR_LBT_MODE])
  839. return -EINVAL;
  840. mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
  841. if (mode != 0 && mode != 1)
  842. return -EINVAL;
  843. if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
  844. return -EINVAL;
  845. return rdev_set_lbt_mode(rdev, wpan_dev, mode);
  846. }
  847. static int
  848. nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
  849. {
  850. struct cfg802154_registered_device *rdev = info->user_ptr[0];
  851. struct net_device *dev = info->user_ptr[1];
  852. struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
  853. int ackreq;
  854. if (netif_running(dev))
  855. return -EBUSY;
  856. if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
  857. return -EINVAL;
  858. ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
  859. if (ackreq != 0 && ackreq != 1)
  860. return -EINVAL;
  861. return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
  862. }
  863. #define NL802154_FLAG_NEED_WPAN_PHY 0x01
  864. #define NL802154_FLAG_NEED_NETDEV 0x02
  865. #define NL802154_FLAG_NEED_RTNL 0x04
  866. #define NL802154_FLAG_CHECK_NETDEV_UP 0x08
  867. #define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\
  868. NL802154_FLAG_CHECK_NETDEV_UP)
  869. #define NL802154_FLAG_NEED_WPAN_DEV 0x10
  870. #define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\
  871. NL802154_FLAG_CHECK_NETDEV_UP)
  872. static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
  873. struct genl_info *info)
  874. {
  875. struct cfg802154_registered_device *rdev;
  876. struct wpan_dev *wpan_dev;
  877. struct net_device *dev;
  878. bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
  879. if (rtnl)
  880. rtnl_lock();
  881. if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
  882. rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
  883. if (IS_ERR(rdev)) {
  884. if (rtnl)
  885. rtnl_unlock();
  886. return PTR_ERR(rdev);
  887. }
  888. info->user_ptr[0] = rdev;
  889. } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
  890. ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
  891. ASSERT_RTNL();
  892. wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
  893. info->attrs);
  894. if (IS_ERR(wpan_dev)) {
  895. if (rtnl)
  896. rtnl_unlock();
  897. return PTR_ERR(wpan_dev);
  898. }
  899. dev = wpan_dev->netdev;
  900. rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
  901. if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
  902. if (!dev) {
  903. if (rtnl)
  904. rtnl_unlock();
  905. return -EINVAL;
  906. }
  907. info->user_ptr[1] = dev;
  908. } else {
  909. info->user_ptr[1] = wpan_dev;
  910. }
  911. if (dev) {
  912. if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
  913. !netif_running(dev)) {
  914. if (rtnl)
  915. rtnl_unlock();
  916. return -ENETDOWN;
  917. }
  918. dev_hold(dev);
  919. }
  920. info->user_ptr[0] = rdev;
  921. }
  922. return 0;
  923. }
  924. static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
  925. struct genl_info *info)
  926. {
  927. if (info->user_ptr[1]) {
  928. if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
  929. struct wpan_dev *wpan_dev = info->user_ptr[1];
  930. if (wpan_dev->netdev)
  931. dev_put(wpan_dev->netdev);
  932. } else {
  933. dev_put(info->user_ptr[1]);
  934. }
  935. }
  936. if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
  937. rtnl_unlock();
  938. }
  939. static const struct genl_ops nl802154_ops[] = {
  940. {
  941. .cmd = NL802154_CMD_GET_WPAN_PHY,
  942. .doit = nl802154_get_wpan_phy,
  943. .dumpit = nl802154_dump_wpan_phy,
  944. .done = nl802154_dump_wpan_phy_done,
  945. .policy = nl802154_policy,
  946. /* can be retrieved by unprivileged users */
  947. .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
  948. NL802154_FLAG_NEED_RTNL,
  949. },
  950. {
  951. .cmd = NL802154_CMD_GET_INTERFACE,
  952. .doit = nl802154_get_interface,
  953. .dumpit = nl802154_dump_interface,
  954. .policy = nl802154_policy,
  955. /* can be retrieved by unprivileged users */
  956. .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
  957. NL802154_FLAG_NEED_RTNL,
  958. },
  959. {
  960. .cmd = NL802154_CMD_NEW_INTERFACE,
  961. .doit = nl802154_new_interface,
  962. .policy = nl802154_policy,
  963. .flags = GENL_ADMIN_PERM,
  964. .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
  965. NL802154_FLAG_NEED_RTNL,
  966. },
  967. {
  968. .cmd = NL802154_CMD_DEL_INTERFACE,
  969. .doit = nl802154_del_interface,
  970. .policy = nl802154_policy,
  971. .flags = GENL_ADMIN_PERM,
  972. .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
  973. NL802154_FLAG_NEED_RTNL,
  974. },
  975. {
  976. .cmd = NL802154_CMD_SET_CHANNEL,
  977. .doit = nl802154_set_channel,
  978. .policy = nl802154_policy,
  979. .flags = GENL_ADMIN_PERM,
  980. .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
  981. NL802154_FLAG_NEED_RTNL,
  982. },
  983. {
  984. .cmd = NL802154_CMD_SET_CCA_MODE,
  985. .doit = nl802154_set_cca_mode,
  986. .policy = nl802154_policy,
  987. .flags = GENL_ADMIN_PERM,
  988. .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
  989. NL802154_FLAG_NEED_RTNL,
  990. },
  991. {
  992. .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
  993. .doit = nl802154_set_cca_ed_level,
  994. .policy = nl802154_policy,
  995. .flags = GENL_ADMIN_PERM,
  996. .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
  997. NL802154_FLAG_NEED_RTNL,
  998. },
  999. {
  1000. .cmd = NL802154_CMD_SET_TX_POWER,
  1001. .doit = nl802154_set_tx_power,
  1002. .policy = nl802154_policy,
  1003. .flags = GENL_ADMIN_PERM,
  1004. .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
  1005. NL802154_FLAG_NEED_RTNL,
  1006. },
  1007. {
  1008. .cmd = NL802154_CMD_SET_PAN_ID,
  1009. .doit = nl802154_set_pan_id,
  1010. .policy = nl802154_policy,
  1011. .flags = GENL_ADMIN_PERM,
  1012. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1013. NL802154_FLAG_NEED_RTNL,
  1014. },
  1015. {
  1016. .cmd = NL802154_CMD_SET_SHORT_ADDR,
  1017. .doit = nl802154_set_short_addr,
  1018. .policy = nl802154_policy,
  1019. .flags = GENL_ADMIN_PERM,
  1020. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1021. NL802154_FLAG_NEED_RTNL,
  1022. },
  1023. {
  1024. .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
  1025. .doit = nl802154_set_backoff_exponent,
  1026. .policy = nl802154_policy,
  1027. .flags = GENL_ADMIN_PERM,
  1028. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1029. NL802154_FLAG_NEED_RTNL,
  1030. },
  1031. {
  1032. .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
  1033. .doit = nl802154_set_max_csma_backoffs,
  1034. .policy = nl802154_policy,
  1035. .flags = GENL_ADMIN_PERM,
  1036. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1037. NL802154_FLAG_NEED_RTNL,
  1038. },
  1039. {
  1040. .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
  1041. .doit = nl802154_set_max_frame_retries,
  1042. .policy = nl802154_policy,
  1043. .flags = GENL_ADMIN_PERM,
  1044. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1045. NL802154_FLAG_NEED_RTNL,
  1046. },
  1047. {
  1048. .cmd = NL802154_CMD_SET_LBT_MODE,
  1049. .doit = nl802154_set_lbt_mode,
  1050. .policy = nl802154_policy,
  1051. .flags = GENL_ADMIN_PERM,
  1052. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1053. NL802154_FLAG_NEED_RTNL,
  1054. },
  1055. {
  1056. .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
  1057. .doit = nl802154_set_ackreq_default,
  1058. .policy = nl802154_policy,
  1059. .flags = GENL_ADMIN_PERM,
  1060. .internal_flags = NL802154_FLAG_NEED_NETDEV |
  1061. NL802154_FLAG_NEED_RTNL,
  1062. },
  1063. };
  1064. /* initialisation/exit functions */
  1065. int nl802154_init(void)
  1066. {
  1067. return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
  1068. nl802154_mcgrps);
  1069. }
  1070. void nl802154_exit(void)
  1071. {
  1072. genl_unregister_family(&nl802154_fam);
  1073. }