Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ieee802154: add support for creation/removal of logic interfaces

Add support for two more NL802154 commands: ADD_IFACE and DEL_IFACE,
thus allowing creation and removal of logic WPAN interfaces on the top
of wpan-phy.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>

+162
+2
include/linux/nl802154.h
··· 118 118 119 119 IEEE802154_LIST_IFACE, 120 120 IEEE802154_LIST_PHY, 121 + IEEE802154_ADD_IFACE, 122 + IEEE802154_DEL_IFACE, 121 123 122 124 __IEEE802154_CMD_MAX, 123 125 };
+4
include/net/wpan-phy.h
··· 41 41 struct device dev; 42 42 int idx; 43 43 44 + struct net_device *(*add_iface)(struct wpan_phy *phy, 45 + const char *name); 46 + void (*del_iface)(struct wpan_phy *phy, struct net_device *dev); 47 + 44 48 char priv[0] __attribute__((__aligned__(NETDEV_ALIGN))); 45 49 }; 46 50
+156
net/ieee802154/nl-phy.c
··· 26 26 #include <net/netlink.h> 27 27 #include <net/genetlink.h> 28 28 #include <net/wpan-phy.h> 29 + #include <net/af_ieee802154.h> 30 + #include <net/ieee802154_netdev.h> 31 + #include <net/rtnetlink.h> /* for rtnl_{un,}lock */ 29 32 #include <linux/nl802154.h> 30 33 31 34 #include "ieee802154.h" ··· 167 164 return skb->len; 168 165 } 169 166 167 + static int ieee802154_add_iface(struct sk_buff *skb, 168 + struct genl_info *info) 169 + { 170 + struct sk_buff *msg; 171 + struct wpan_phy *phy; 172 + const char *name; 173 + const char *devname; 174 + int rc = -ENOBUFS; 175 + struct net_device *dev; 176 + 177 + pr_debug("%s\n", __func__); 178 + 179 + if (!info->attrs[IEEE802154_ATTR_PHY_NAME]) 180 + return -EINVAL; 181 + 182 + name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 183 + if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0') 184 + return -EINVAL; /* phy name should be null-terminated */ 185 + 186 + if (info->attrs[IEEE802154_ATTR_DEV_NAME]) { 187 + devname = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); 188 + if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] 189 + != '\0') 190 + return -EINVAL; /* phy name should be null-terminated */ 191 + } else { 192 + devname = "wpan%d"; 193 + } 194 + 195 + if (strlen(devname) >= IFNAMSIZ) 196 + return -ENAMETOOLONG; 197 + 198 + phy = wpan_phy_find(name); 199 + if (!phy) 200 + return -ENODEV; 201 + 202 + msg = ieee802154_nl_new_reply(info, 0, IEEE802154_ADD_IFACE); 203 + if (!msg) 204 + goto out_dev; 205 + 206 + if (!phy->add_iface) { 207 + rc = -EINVAL; 208 + goto nla_put_failure; 209 + } 210 + 211 + dev = phy->add_iface(phy, devname); 212 + if (IS_ERR(dev)) { 213 + rc = PTR_ERR(dev); 214 + goto nla_put_failure; 215 + } 216 + 217 + NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); 218 + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, dev->name); 219 + 220 + dev_put(dev); 221 + 222 + wpan_phy_put(phy); 223 + 224 + return ieee802154_nl_reply(msg, info); 225 + 226 + nla_put_failure: 227 + nlmsg_free(msg); 228 + out_dev: 229 + wpan_phy_put(phy); 230 + return rc; 231 + } 232 + 233 + static int ieee802154_del_iface(struct sk_buff *skb, 234 + struct genl_info *info) 235 + { 236 + struct sk_buff *msg; 237 + struct wpan_phy *phy; 238 + const char *name; 239 + int rc; 240 + struct net_device *dev; 241 + 242 + pr_debug("%s\n", __func__); 243 + 244 + if (!info->attrs[IEEE802154_ATTR_DEV_NAME]) 245 + return -EINVAL; 246 + 247 + name = nla_data(info->attrs[IEEE802154_ATTR_DEV_NAME]); 248 + if (name[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') 249 + return -EINVAL; /* name should be null-terminated */ 250 + 251 + dev = dev_get_by_name(genl_info_net(info), name); 252 + if (!dev) 253 + return -ENODEV; 254 + 255 + phy = ieee802154_mlme_ops(dev)->get_phy(dev); 256 + BUG_ON(!phy); 257 + 258 + rc = -EINVAL; 259 + /* phy name is optional, but should be checked if it's given */ 260 + if (info->attrs[IEEE802154_ATTR_PHY_NAME]) { 261 + struct wpan_phy *phy2; 262 + 263 + const char *pname = 264 + nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]); 265 + if (pname[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] 266 + != '\0') 267 + /* name should be null-terminated */ 268 + goto out_dev; 269 + 270 + phy2 = wpan_phy_find(pname); 271 + if (!phy2) 272 + goto out_dev; 273 + 274 + if (phy != phy2) { 275 + wpan_phy_put(phy2); 276 + goto out_dev; 277 + } 278 + } 279 + 280 + rc = -ENOBUFS; 281 + 282 + msg = ieee802154_nl_new_reply(info, 0, IEEE802154_DEL_IFACE); 283 + if (!msg) 284 + goto out_dev; 285 + 286 + if (!phy->del_iface) { 287 + rc = -EINVAL; 288 + goto nla_put_failure; 289 + } 290 + 291 + rtnl_lock(); 292 + phy->del_iface(phy, dev); 293 + 294 + /* We don't have device anymore */ 295 + dev_put(dev); 296 + dev = NULL; 297 + 298 + rtnl_unlock(); 299 + 300 + 301 + NLA_PUT_STRING(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)); 302 + NLA_PUT_STRING(msg, IEEE802154_ATTR_DEV_NAME, name); 303 + 304 + wpan_phy_put(phy); 305 + 306 + return ieee802154_nl_reply(msg, info); 307 + 308 + nla_put_failure: 309 + nlmsg_free(msg); 310 + out_dev: 311 + wpan_phy_put(phy); 312 + if (dev) 313 + dev_put(dev); 314 + 315 + return rc; 316 + } 317 + 170 318 static struct genl_ops ieee802154_phy_ops[] = { 171 319 IEEE802154_DUMP(IEEE802154_LIST_PHY, ieee802154_list_phy, 172 320 ieee802154_dump_phy), 321 + IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface), 322 + IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface), 173 323 }; 174 324 175 325 /*