~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ieee802154/nl-phy.c

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Netlink interface for IEEE 802.15.4 stack
  4  *
  5  * Copyright 2007, 2008 Siemens AG
  6  *
  7  * Written by:
  8  * Sergey Lapin <slapin@ossfans.org>
  9  * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 10  * Maxim Osipov <maxim.osipov@siemens.com>
 11  */
 12 
 13 #include <linux/kernel.h>
 14 #include <linux/slab.h>
 15 #include <linux/if_arp.h>
 16 #include <net/netlink.h>
 17 #include <net/genetlink.h>
 18 #include <net/cfg802154.h>
 19 #include <net/af_ieee802154.h>
 20 #include <net/ieee802154_netdev.h>
 21 #include <net/rtnetlink.h> /* for rtnl_{un,}lock */
 22 #include <linux/nl802154.h>
 23 
 24 #include "ieee802154.h"
 25 #include "rdev-ops.h"
 26 #include "core.h"
 27 
 28 static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
 29                                   u32 seq, int flags, struct wpan_phy *phy)
 30 {
 31         void *hdr;
 32         int i, pages = 0;
 33         uint32_t *buf = kcalloc(32, sizeof(uint32_t), GFP_KERNEL);
 34 
 35         pr_debug("%s\n", __func__);
 36 
 37         if (!buf)
 38                 return -EMSGSIZE;
 39 
 40         hdr = genlmsg_put(msg, 0, seq, &nl802154_family, flags,
 41                           IEEE802154_LIST_PHY);
 42         if (!hdr)
 43                 goto out;
 44 
 45         rtnl_lock();
 46         if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
 47             nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) ||
 48             nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel))
 49                 goto nla_put_failure;
 50         for (i = 0; i < 32; i++) {
 51                 if (phy->supported.channels[i])
 52                         buf[pages++] = phy->supported.channels[i] | (i << 27);
 53         }
 54         if (pages &&
 55             nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
 56                     pages * sizeof(uint32_t), buf))
 57                 goto nla_put_failure;
 58         rtnl_unlock();
 59         kfree(buf);
 60         genlmsg_end(msg, hdr);
 61         return 0;
 62 
 63 nla_put_failure:
 64         rtnl_unlock();
 65         genlmsg_cancel(msg, hdr);
 66 out:
 67         kfree(buf);
 68         return -EMSGSIZE;
 69 }
 70 
 71 int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info)
 72 {
 73         /* Request for interface name, index, type, IEEE address,
 74          * PAN Id, short address
 75          */
 76         struct sk_buff *msg;
 77         struct wpan_phy *phy;
 78         const char *name;
 79         int rc = -ENOBUFS;
 80 
 81         pr_debug("%s\n", __func__);
 82 
 83         if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
 84                 return -EINVAL;
 85 
 86         name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
 87         if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
 88                 return -EINVAL; /* phy name should be null-terminated */
 89 
 90         phy = wpan_phy_find(name);
 91         if (!phy)
 92                 return -ENODEV;
 93 
 94         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 95         if (!msg)
 96                 goto out_dev;
 97 
 98         rc = ieee802154_nl_fill_phy(msg, info->snd_portid, info->snd_seq,
 99                                     0, phy);
100         if (rc < 0)
101                 goto out_free;
102 
103         wpan_phy_put(phy);
104 
105         return genlmsg_reply(msg, info);
106 out_free:
107         nlmsg_free(msg);
108 out_dev:
109         wpan_phy_put(phy);
110         return rc;
111 }
112 
113 struct dump_phy_data {
114         struct sk_buff *skb;
115         struct netlink_callback *cb;
116         int idx, s_idx;
117 };
118 
119 static int ieee802154_dump_phy_iter(struct wpan_phy *phy, void *_data)
120 {
121         int rc;
122         struct dump_phy_data *data = _data;
123 
124         pr_debug("%s\n", __func__);
125 
126         if (data->idx++ < data->s_idx)
127                 return 0;
128 
129         rc = ieee802154_nl_fill_phy(data->skb,
130                                     NETLINK_CB(data->cb->skb).portid,
131                                     data->cb->nlh->nlmsg_seq,
132                                     NLM_F_MULTI,
133                                     phy);
134 
135         if (rc < 0) {
136                 data->idx--;
137                 return rc;
138         }
139 
140         return 0;
141 }
142 
143 int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb)
144 {
145         struct dump_phy_data data = {
146                 .cb = cb,
147                 .skb = skb,
148                 .s_idx = cb->args[0],
149                 .idx = 0,
150         };
151 
152         pr_debug("%s\n", __func__);
153 
154         wpan_phy_for_each(ieee802154_dump_phy_iter, &data);
155 
156         cb->args[0] = data.idx;
157 
158         return skb->len;
159 }
160 
161 int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
162 {
163         struct sk_buff *msg;
164         struct wpan_phy *phy;
165         const char *name;
166         const char *devname;
167         int rc = -ENOBUFS;
168         struct net_device *dev;
169         int type = __IEEE802154_DEV_INVALID;
170         unsigned char name_assign_type;
171 
172         pr_debug("%s\n", __func__);
173 
174         if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
175                 return -EINVAL;
176 
177         name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
178         if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
179                 return -EINVAL; /* phy name should be null-terminated */
180 
181         if (info->attrs[IEEE802154_ATTR_DEV_NAME]) {
182                 devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
183                 if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1]
184                                 != '\0')
185                         return -EINVAL; /* phy name should be null-terminated */
186                 name_assign_type = NET_NAME_USER;
187         } else  {
188                 devname = "wpan%d";
189                 name_assign_type = NET_NAME_ENUM;
190         }
191 
192         if (strlen(devname) >= IFNAMSIZ)
193                 return -ENAMETOOLONG;
194 
195         phy = wpan_phy_find(name);
196         if (!phy)
197                 return -ENODEV;
198 
199         msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE);
200         if (!msg)
201                 goto out_dev;
202 
203         if (info->attrs[IEEE802154_ATTR_HW_ADDR] &&
204             nla_len(info->attrs[IEEE802154_ATTR_HW_ADDR]) !=
205                         IEEE802154_ADDR_LEN) {
206                 rc = -EINVAL;
207                 goto nla_put_failure;
208         }
209 
210         if (info->attrs[IEEE802154_ATTR_DEV_TYPE]) {
211                 type = nla_get_u8(info->attrs[IEEE802154_ATTR_DEV_TYPE]);
212                 if (type >= __IEEE802154_DEV_MAX) {
213                         rc = -EINVAL;
214                         goto nla_put_failure;
215                 }
216         }
217 
218         dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname,
219                                                name_assign_type, type);
220         if (IS_ERR(dev)) {
221                 rc = PTR_ERR(dev);
222                 goto nla_put_failure;
223         }
224         dev_hold(dev);
225 
226         if (info->attrs[IEEE802154_ATTR_HW_ADDR]) {
227                 struct sockaddr addr;
228 
229                 addr.sa_family = ARPHRD_IEEE802154;
230                 nla_memcpy(&addr.sa_data, info->attrs[IEEE802154_ATTR_HW_ADDR],
231                            IEEE802154_ADDR_LEN);
232 
233                 /* strangely enough, some callbacks (inetdev_event) from
234                  * dev_set_mac_address require RTNL_LOCK
235                  */
236                 rtnl_lock();
237                 rc = dev_set_mac_address(dev, &addr, NULL);
238                 rtnl_unlock();
239                 if (rc)
240                         goto dev_unregister;
241         }
242 
243         if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
244             nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name))
245                 goto nla_put_failure;
246         dev_put(dev);
247 
248         wpan_phy_put(phy);
249 
250         return ieee802154_nl_reply(msg, info);
251 
252 dev_unregister:
253         rtnl_lock(); /* del_iface must be called with RTNL lock */
254         rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev);
255         dev_put(dev);
256         rtnl_unlock();
257 nla_put_failure:
258         nlmsg_free(msg);
259 out_dev:
260         wpan_phy_put(phy);
261         return rc;
262 }
263 
264 int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info)
265 {
266         struct sk_buff *msg;
267         struct wpan_phy *phy;
268         const char *name;
269         int rc;
270         struct net_device *dev;
271 
272         pr_debug("%s\n", __func__);
273 
274         if (!info->attrs[IEEE802154_ATTR_DEV_NAME])
275                 return -EINVAL;
276 
277         name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]);
278         if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0')
279                 return -EINVAL; /* name should be null-terminated */
280 
281         rc = -ENODEV;
282         dev = dev_get_by_name(genl_info_net(info), name);
283         if (!dev)
284                 return rc;
285         if (dev->type != ARPHRD_IEEE802154)
286                 goto out;
287 
288         phy = dev->ieee802154_ptr->wpan_phy;
289         BUG_ON(!phy);
290         get_device(&phy->dev);
291 
292         rc = -EINVAL;
293         /* phy name is optional, but should be checked if it's given */
294         if (info->attrs[IEEE802154_ATTR_PHY_NAME]) {
295                 struct wpan_phy *phy2;
296 
297                 const char *pname =
298                         nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
299                 if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1]
300                                 != '\0')
301                         /* name should be null-terminated */
302                         goto out_dev;
303 
304                 phy2 = wpan_phy_find(pname);
305                 if (!phy2)
306                         goto out_dev;
307 
308                 if (phy != phy2) {
309                         wpan_phy_put(phy2);
310                         goto out_dev;
311                 }
312         }
313 
314         rc = -ENOBUFS;
315 
316         msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE);
317         if (!msg)
318                 goto out_dev;
319 
320         rtnl_lock();
321         rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev);
322 
323         /* We don't have device anymore */
324         dev_put(dev);
325         dev = NULL;
326 
327         rtnl_unlock();
328 
329         if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
330             nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, name))
331                 goto nla_put_failure;
332         wpan_phy_put(phy);
333 
334         return ieee802154_nl_reply(msg, info);
335 
336 nla_put_failure:
337         nlmsg_free(msg);
338 out_dev:
339         wpan_phy_put(phy);
340 out:
341         if (dev)
342                 dev_put(dev);
343 
344         return rc;
345 }
346 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp