nl-mac.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. /*
  2. * Netlink inteface for IEEE 802.15.4 stack
  3. *
  4. * Copyright 2007, 2008 Siemens AG
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2
  8. * as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, write to the Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. *
  19. * Written by:
  20. * Sergey Lapin <slapin@ossfans.org>
  21. * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
  22. * Maxim Osipov <maxim.osipov@siemens.com>
  23. */
  24. #include <linux/gfp.h>
  25. #include <linux/kernel.h>
  26. #include <linux/if_arp.h>
  27. #include <linux/netdevice.h>
  28. #include <net/netlink.h>
  29. #include <net/genetlink.h>
  30. #include <net/sock.h>
  31. #include <linux/nl802154.h>
  32. #include <linux/export.h>
  33. #include <net/af_ieee802154.h>
  34. #include <net/nl802154.h>
  35. #include <net/ieee802154.h>
  36. #include <net/ieee802154_netdev.h>
  37. #include <net/wpan-phy.h>
  38. #include "ieee802154.h"
  39. static int nla_put_hwaddr(struct sk_buff *msg, int type, __le64 hwaddr)
  40. {
  41. return nla_put_u64(msg, type, swab64((__force u64)hwaddr));
  42. }
  43. static __le64 nla_get_hwaddr(const struct nlattr *nla)
  44. {
  45. return ieee802154_devaddr_from_raw(nla_data(nla));
  46. }
  47. static int nla_put_shortaddr(struct sk_buff *msg, int type, __le16 addr)
  48. {
  49. return nla_put_u16(msg, type, le16_to_cpu(addr));
  50. }
  51. static __le16 nla_get_shortaddr(const struct nlattr *nla)
  52. {
  53. return cpu_to_le16(nla_get_u16(nla));
  54. }
  55. int ieee802154_nl_assoc_indic(struct net_device *dev,
  56. struct ieee802154_addr *addr, u8 cap)
  57. {
  58. struct sk_buff *msg;
  59. pr_debug("%s\n", __func__);
  60. if (addr->mode != IEEE802154_ADDR_LONG) {
  61. pr_err("%s: received non-long source address!\n", __func__);
  62. return -EINVAL;
  63. }
  64. msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
  65. if (!msg)
  66. return -ENOBUFS;
  67. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  68. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  69. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  70. dev->dev_addr) ||
  71. nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
  72. addr->extended_addr) ||
  73. nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
  74. goto nla_put_failure;
  75. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  76. nla_put_failure:
  77. nlmsg_free(msg);
  78. return -ENOBUFS;
  79. }
  80. EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
  81. int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr,
  82. u8 status)
  83. {
  84. struct sk_buff *msg;
  85. pr_debug("%s\n", __func__);
  86. msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
  87. if (!msg)
  88. return -ENOBUFS;
  89. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  90. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  91. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  92. dev->dev_addr) ||
  93. nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
  94. nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
  95. goto nla_put_failure;
  96. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  97. nla_put_failure:
  98. nlmsg_free(msg);
  99. return -ENOBUFS;
  100. }
  101. EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
  102. int ieee802154_nl_disassoc_indic(struct net_device *dev,
  103. struct ieee802154_addr *addr, u8 reason)
  104. {
  105. struct sk_buff *msg;
  106. pr_debug("%s\n", __func__);
  107. msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
  108. if (!msg)
  109. return -ENOBUFS;
  110. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  111. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  112. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  113. dev->dev_addr))
  114. goto nla_put_failure;
  115. if (addr->mode == IEEE802154_ADDR_LONG) {
  116. if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
  117. addr->extended_addr))
  118. goto nla_put_failure;
  119. } else {
  120. if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
  121. addr->short_addr))
  122. goto nla_put_failure;
  123. }
  124. if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
  125. goto nla_put_failure;
  126. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  127. nla_put_failure:
  128. nlmsg_free(msg);
  129. return -ENOBUFS;
  130. }
  131. EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
  132. int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
  133. {
  134. struct sk_buff *msg;
  135. pr_debug("%s\n", __func__);
  136. msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
  137. if (!msg)
  138. return -ENOBUFS;
  139. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  140. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  141. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  142. dev->dev_addr) ||
  143. nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
  144. goto nla_put_failure;
  145. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  146. nla_put_failure:
  147. nlmsg_free(msg);
  148. return -ENOBUFS;
  149. }
  150. EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
  151. int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
  152. __le16 coord_addr)
  153. {
  154. struct sk_buff *msg;
  155. pr_debug("%s\n", __func__);
  156. msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
  157. if (!msg)
  158. return -ENOBUFS;
  159. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  160. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  161. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  162. dev->dev_addr) ||
  163. nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR,
  164. coord_addr) ||
  165. nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
  166. goto nla_put_failure;
  167. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  168. nla_put_failure:
  169. nlmsg_free(msg);
  170. return -ENOBUFS;
  171. }
  172. EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
  173. int ieee802154_nl_scan_confirm(struct net_device *dev,
  174. u8 status, u8 scan_type, u32 unscanned, u8 page,
  175. u8 *edl/* , struct list_head *pan_desc_list */)
  176. {
  177. struct sk_buff *msg;
  178. pr_debug("%s\n", __func__);
  179. msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
  180. if (!msg)
  181. return -ENOBUFS;
  182. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  183. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  184. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  185. dev->dev_addr) ||
  186. nla_put_u8(msg, IEEE802154_ATTR_STATUS, status) ||
  187. nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
  188. nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
  189. nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
  190. (edl &&
  191. nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
  192. goto nla_put_failure;
  193. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  194. nla_put_failure:
  195. nlmsg_free(msg);
  196. return -ENOBUFS;
  197. }
  198. EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
  199. int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
  200. {
  201. struct sk_buff *msg;
  202. pr_debug("%s\n", __func__);
  203. msg = ieee802154_nl_create(0, IEEE802154_START_CONF);
  204. if (!msg)
  205. return -ENOBUFS;
  206. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  207. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  208. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  209. dev->dev_addr) ||
  210. nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
  211. goto nla_put_failure;
  212. return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
  213. nla_put_failure:
  214. nlmsg_free(msg);
  215. return -ENOBUFS;
  216. }
  217. EXPORT_SYMBOL(ieee802154_nl_start_confirm);
  218. static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
  219. u32 seq, int flags, struct net_device *dev)
  220. {
  221. void *hdr;
  222. struct wpan_phy *phy;
  223. struct ieee802154_mlme_ops *ops;
  224. __le16 short_addr, pan_id;
  225. pr_debug("%s\n", __func__);
  226. hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
  227. IEEE802154_LIST_IFACE);
  228. if (!hdr)
  229. goto out;
  230. ops = ieee802154_mlme_ops(dev);
  231. phy = ops->get_phy(dev);
  232. BUG_ON(!phy);
  233. short_addr = ops->get_short_addr(dev);
  234. pan_id = ops->get_pan_id(dev);
  235. if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
  236. nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
  237. nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
  238. nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
  239. dev->dev_addr) ||
  240. nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
  241. nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id))
  242. goto nla_put_failure;
  243. if (ops->get_mac_params) {
  244. struct ieee802154_mac_params params;
  245. ops->get_mac_params(dev, &params);
  246. if (nla_put_s8(msg, IEEE802154_ATTR_TXPOWER,
  247. params.transmit_power) ||
  248. nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, params.lbt) ||
  249. nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE,
  250. params.cca_mode) ||
  251. nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL,
  252. params.cca_ed_level) ||
  253. nla_put_u8(msg, IEEE802154_ATTR_CSMA_RETRIES,
  254. params.csma_retries) ||
  255. nla_put_u8(msg, IEEE802154_ATTR_CSMA_MIN_BE,
  256. params.min_be) ||
  257. nla_put_u8(msg, IEEE802154_ATTR_CSMA_MAX_BE,
  258. params.max_be) ||
  259. nla_put_s8(msg, IEEE802154_ATTR_FRAME_RETRIES,
  260. params.frame_retries))
  261. goto nla_put_failure;
  262. }
  263. wpan_phy_put(phy);
  264. return genlmsg_end(msg, hdr);
  265. nla_put_failure:
  266. wpan_phy_put(phy);
  267. genlmsg_cancel(msg, hdr);
  268. out:
  269. return -EMSGSIZE;
  270. }
  271. /* Requests from userspace */
  272. static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
  273. {
  274. struct net_device *dev;
  275. if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
  276. char name[IFNAMSIZ + 1];
  277. nla_strlcpy(name, info->attrs[IEEE802154_ATTR_DEV_NAME],
  278. sizeof(name));
  279. dev = dev_get_by_name(&init_net, name);
  280. } else if (info->attrs[IEEE802154_ATTR_DEV_INDEX])
  281. dev = dev_get_by_index(&init_net,
  282. nla_get_u32(info->attrs[IEEE802154_ATTR_DEV_INDEX]));
  283. else
  284. return NULL;
  285. if (!dev)
  286. return NULL;
  287. if (dev->type != ARPHRD_IEEE802154) {
  288. dev_put(dev);
  289. return NULL;
  290. }
  291. return dev;
  292. }
  293. int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
  294. {
  295. struct net_device *dev;
  296. struct ieee802154_addr addr;
  297. u8 page;
  298. int ret = -EOPNOTSUPP;
  299. if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
  300. !info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
  301. (!info->attrs[IEEE802154_ATTR_COORD_HW_ADDR] &&
  302. !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]) ||
  303. !info->attrs[IEEE802154_ATTR_CAPABILITY])
  304. return -EINVAL;
  305. dev = ieee802154_nl_get_dev(info);
  306. if (!dev)
  307. return -ENODEV;
  308. if (!ieee802154_mlme_ops(dev)->assoc_req)
  309. goto out;
  310. if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
  311. addr.mode = IEEE802154_ADDR_LONG;
  312. addr.extended_addr = nla_get_hwaddr(
  313. info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]);
  314. } else {
  315. addr.mode = IEEE802154_ADDR_SHORT;
  316. addr.short_addr = nla_get_shortaddr(
  317. info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
  318. }
  319. addr.pan_id = nla_get_shortaddr(
  320. info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
  321. if (info->attrs[IEEE802154_ATTR_PAGE])
  322. page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
  323. else
  324. page = 0;
  325. ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
  326. nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
  327. page,
  328. nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
  329. out:
  330. dev_put(dev);
  331. return ret;
  332. }
  333. int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
  334. {
  335. struct net_device *dev;
  336. struct ieee802154_addr addr;
  337. int ret = -EOPNOTSUPP;
  338. if (!info->attrs[IEEE802154_ATTR_STATUS] ||
  339. !info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] ||
  340. !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR])
  341. return -EINVAL;
  342. dev = ieee802154_nl_get_dev(info);
  343. if (!dev)
  344. return -ENODEV;
  345. if (!ieee802154_mlme_ops(dev)->assoc_resp)
  346. goto out;
  347. addr.mode = IEEE802154_ADDR_LONG;
  348. addr.extended_addr = nla_get_hwaddr(
  349. info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
  350. addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
  351. ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
  352. nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
  353. nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
  354. out:
  355. dev_put(dev);
  356. return ret;
  357. }
  358. int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
  359. {
  360. struct net_device *dev;
  361. struct ieee802154_addr addr;
  362. int ret = -EOPNOTSUPP;
  363. if ((!info->attrs[IEEE802154_ATTR_DEST_HW_ADDR] &&
  364. !info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]) ||
  365. !info->attrs[IEEE802154_ATTR_REASON])
  366. return -EINVAL;
  367. dev = ieee802154_nl_get_dev(info);
  368. if (!dev)
  369. return -ENODEV;
  370. if (!ieee802154_mlme_ops(dev)->disassoc_req)
  371. goto out;
  372. if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
  373. addr.mode = IEEE802154_ADDR_LONG;
  374. addr.extended_addr = nla_get_hwaddr(
  375. info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
  376. } else {
  377. addr.mode = IEEE802154_ADDR_SHORT;
  378. addr.short_addr = nla_get_shortaddr(
  379. info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
  380. }
  381. addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
  382. ret = ieee802154_mlme_ops(dev)->disassoc_req(dev, &addr,
  383. nla_get_u8(info->attrs[IEEE802154_ATTR_REASON]));
  384. out:
  385. dev_put(dev);
  386. return ret;
  387. }
  388. /*
  389. * PANid, channel, beacon_order = 15, superframe_order = 15,
  390. * PAN_coordinator, battery_life_extension = 0,
  391. * coord_realignment = 0, security_enable = 0
  392. */
  393. int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
  394. {
  395. struct net_device *dev;
  396. struct ieee802154_addr addr;
  397. u8 channel, bcn_ord, sf_ord;
  398. u8 page;
  399. int pan_coord, blx, coord_realign;
  400. int ret = -EOPNOTSUPP;
  401. if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
  402. !info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
  403. !info->attrs[IEEE802154_ATTR_CHANNEL] ||
  404. !info->attrs[IEEE802154_ATTR_BCN_ORD] ||
  405. !info->attrs[IEEE802154_ATTR_SF_ORD] ||
  406. !info->attrs[IEEE802154_ATTR_PAN_COORD] ||
  407. !info->attrs[IEEE802154_ATTR_BAT_EXT] ||
  408. !info->attrs[IEEE802154_ATTR_COORD_REALIGN]
  409. )
  410. return -EINVAL;
  411. dev = ieee802154_nl_get_dev(info);
  412. if (!dev)
  413. return -ENODEV;
  414. if (!ieee802154_mlme_ops(dev)->start_req)
  415. goto out;
  416. addr.mode = IEEE802154_ADDR_SHORT;
  417. addr.short_addr = nla_get_shortaddr(
  418. info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
  419. addr.pan_id = nla_get_shortaddr(
  420. info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
  421. channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
  422. bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
  423. sf_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_SF_ORD]);
  424. pan_coord = nla_get_u8(info->attrs[IEEE802154_ATTR_PAN_COORD]);
  425. blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
  426. coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
  427. if (info->attrs[IEEE802154_ATTR_PAGE])
  428. page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
  429. else
  430. page = 0;
  431. if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
  432. ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
  433. dev_put(dev);
  434. return -EINVAL;
  435. }
  436. ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
  437. bcn_ord, sf_ord, pan_coord, blx, coord_realign);
  438. out:
  439. dev_put(dev);
  440. return ret;
  441. }
  442. int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
  443. {
  444. struct net_device *dev;
  445. int ret = -EOPNOTSUPP;
  446. u8 type;
  447. u32 channels;
  448. u8 duration;
  449. u8 page;
  450. if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
  451. !info->attrs[IEEE802154_ATTR_CHANNELS] ||
  452. !info->attrs[IEEE802154_ATTR_DURATION])
  453. return -EINVAL;
  454. dev = ieee802154_nl_get_dev(info);
  455. if (!dev)
  456. return -ENODEV;
  457. if (!ieee802154_mlme_ops(dev)->scan_req)
  458. goto out;
  459. type = nla_get_u8(info->attrs[IEEE802154_ATTR_SCAN_TYPE]);
  460. channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
  461. duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
  462. if (info->attrs[IEEE802154_ATTR_PAGE])
  463. page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
  464. else
  465. page = 0;
  466. ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
  467. duration);
  468. out:
  469. dev_put(dev);
  470. return ret;
  471. }
  472. int ieee802154_list_iface(struct sk_buff *skb, struct genl_info *info)
  473. {
  474. /* Request for interface name, index, type, IEEE address,
  475. PAN Id, short address */
  476. struct sk_buff *msg;
  477. struct net_device *dev = NULL;
  478. int rc = -ENOBUFS;
  479. pr_debug("%s\n", __func__);
  480. dev = ieee802154_nl_get_dev(info);
  481. if (!dev)
  482. return -ENODEV;
  483. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  484. if (!msg)
  485. goto out_dev;
  486. rc = ieee802154_nl_fill_iface(msg, info->snd_portid, info->snd_seq,
  487. 0, dev);
  488. if (rc < 0)
  489. goto out_free;
  490. dev_put(dev);
  491. return genlmsg_reply(msg, info);
  492. out_free:
  493. nlmsg_free(msg);
  494. out_dev:
  495. dev_put(dev);
  496. return rc;
  497. }
  498. int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
  499. {
  500. struct net *net = sock_net(skb->sk);
  501. struct net_device *dev;
  502. int idx;
  503. int s_idx = cb->args[0];
  504. pr_debug("%s\n", __func__);
  505. idx = 0;
  506. for_each_netdev(net, dev) {
  507. if (idx < s_idx || (dev->type != ARPHRD_IEEE802154))
  508. goto cont;
  509. if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
  510. cb->nlh->nlmsg_seq, NLM_F_MULTI, dev) < 0)
  511. break;
  512. cont:
  513. idx++;
  514. }
  515. cb->args[0] = idx;
  516. return skb->len;
  517. }
  518. int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info)
  519. {
  520. struct net_device *dev = NULL;
  521. struct ieee802154_mlme_ops *ops;
  522. struct ieee802154_mac_params params;
  523. struct wpan_phy *phy;
  524. int rc = -EINVAL;
  525. pr_debug("%s\n", __func__);
  526. dev = ieee802154_nl_get_dev(info);
  527. if (!dev)
  528. return -ENODEV;
  529. ops = ieee802154_mlme_ops(dev);
  530. if (!ops->get_mac_params || !ops->set_mac_params) {
  531. rc = -EOPNOTSUPP;
  532. goto out;
  533. }
  534. if (netif_running(dev)) {
  535. rc = -EBUSY;
  536. goto out;
  537. }
  538. if (!info->attrs[IEEE802154_ATTR_LBT_ENABLED] &&
  539. !info->attrs[IEEE802154_ATTR_CCA_MODE] &&
  540. !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL] &&
  541. !info->attrs[IEEE802154_ATTR_CSMA_RETRIES] &&
  542. !info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] &&
  543. !info->attrs[IEEE802154_ATTR_CSMA_MAX_BE] &&
  544. !info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
  545. goto out;
  546. phy = ops->get_phy(dev);
  547. if ((!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
  548. (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
  549. (!phy->set_cca_ed_level &&
  550. info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) ||
  551. (!phy->set_csma_params &&
  552. (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] ||
  553. info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] ||
  554. info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])) ||
  555. (!phy->set_frame_retries &&
  556. info->attrs[IEEE802154_ATTR_FRAME_RETRIES])) {
  557. rc = -EOPNOTSUPP;
  558. goto out_phy;
  559. }
  560. ops->get_mac_params(dev, &params);
  561. if (info->attrs[IEEE802154_ATTR_TXPOWER])
  562. params.transmit_power = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]);
  563. if (info->attrs[IEEE802154_ATTR_LBT_ENABLED])
  564. params.lbt = nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]);
  565. if (info->attrs[IEEE802154_ATTR_CCA_MODE])
  566. params.cca_mode = nla_get_u8(info->attrs[IEEE802154_ATTR_CCA_MODE]);
  567. if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL])
  568. params.cca_ed_level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]);
  569. if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES])
  570. params.csma_retries = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_RETRIES]);
  571. if (info->attrs[IEEE802154_ATTR_CSMA_MIN_BE])
  572. params.min_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MIN_BE]);
  573. if (info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])
  574. params.max_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]);
  575. if (info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
  576. params.frame_retries = nla_get_s8(info->attrs[IEEE802154_ATTR_FRAME_RETRIES]);
  577. rc = ops->set_mac_params(dev, &params);
  578. wpan_phy_put(phy);
  579. dev_put(dev);
  580. return rc;
  581. out_phy:
  582. wpan_phy_put(phy);
  583. out:
  584. dev_put(dev);
  585. return rc;
  586. }