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

mctp: Add device handling and netlink interface

This change adds the infrastructure for managing MCTP netdevices; we add
a pointer to the AF_MCTP-specific data to struct netdevice, and hook up
the rtnetlink operations for adding and removing addresses.

Includes changes from Matt Johnston <matt@codeconstruct.com.au>.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jeremy Kerr and committed by
David S. Miller
583be982 4b2e6930

+491 -1
+1
MAINTAINERS
··· 11039 11039 S: Maintained 11040 11040 F: drivers/net/mctp/ 11041 11041 F: include/net/mctp.h 11042 + F: include/net/mctpdevice.h 11042 11043 F: net/mctp/ 11043 11044 11044 11045 MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
+4
include/linux/netdevice.h
··· 1823 1823 * @ieee802154_ptr: IEEE 802.15.4 low-rate Wireless Personal Area Network 1824 1824 * device struct 1825 1825 * @mpls_ptr: mpls_dev struct pointer 1826 + * @mctp_ptr: MCTP specific data 1826 1827 * 1827 1828 * @dev_addr: Hw address (before bcast, 1828 1829 * because most packets are unicast) ··· 2110 2109 struct wpan_dev *ieee802154_ptr; 2111 2110 #if IS_ENABLED(CONFIG_MPLS_ROUTING) 2112 2111 struct mpls_dev __rcu *mpls_ptr; 2112 + #endif 2113 + #if IS_ENABLED(CONFIG_MCTP) 2114 + struct mctp_dev __rcu *mctp_ptr; 2113 2115 #endif 2114 2116 2115 2117 /*
+14
include/net/mctp.h
··· 10 10 #define __NET_MCTP_H 11 11 12 12 #include <linux/bits.h> 13 + #include <linux/mctp.h> 13 14 14 15 /* MCTP packet definitions */ 15 16 struct mctp_hdr { ··· 32 31 #define MCTP_HDR_SEQ_MASK GENMASK(1, 0) 33 32 #define MCTP_HDR_TAG_SHIFT 0 34 33 #define MCTP_HDR_TAG_MASK GENMASK(2, 0) 34 + 35 + static inline bool mctp_address_ok(mctp_eid_t eid) 36 + { 37 + return eid >= 8 && eid < 255; 38 + } 39 + 40 + static inline struct mctp_hdr *mctp_hdr(struct sk_buff *skb) 41 + { 42 + return (struct mctp_hdr *)skb_network_header(skb); 43 + } 44 + 45 + void mctp_device_init(void); 46 + void mctp_device_exit(void); 35 47 36 48 #endif /* __NET_MCTP_H */
+35
include/net/mctpdevice.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Management Component Transport Protocol (MCTP) - device 4 + * definitions. 5 + * 6 + * Copyright (c) 2021 Code Construct 7 + * Copyright (c) 2021 Google 8 + */ 9 + 10 + #ifndef __NET_MCTPDEVICE_H 11 + #define __NET_MCTPDEVICE_H 12 + 13 + #include <linux/list.h> 14 + #include <linux/types.h> 15 + #include <linux/refcount.h> 16 + 17 + struct mctp_dev { 18 + struct net_device *dev; 19 + 20 + unsigned int net; 21 + 22 + /* Only modified under RTNL. Reads have addrs_lock held */ 23 + u8 *addrs; 24 + size_t num_addrs; 25 + spinlock_t addrs_lock; 26 + 27 + struct rcu_head rcu; 28 + }; 29 + 30 + #define MCTP_INITIAL_DEFAULT_NET 1 31 + 32 + struct mctp_dev *mctp_dev_get_rtnl(const struct net_device *dev); 33 + struct mctp_dev *__mctp_dev_get(const struct net_device *dev); 34 + 35 + #endif /* __NET_MCTPDEVICE_H */
+3
include/uapi/linux/if_ether.h
··· 151 151 #define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and 152 152 * aggregation protocol 153 153 */ 154 + #define ETH_P_MCTP 0x00FA /* Management component transport 155 + * protocol packets 156 + */ 154 157 155 158 /* 156 159 * This is an Ethernet frame header.
+10
include/uapi/linux/if_link.h
··· 1260 1260 __u32 mask; 1261 1261 }; 1262 1262 1263 + /* MCTP section */ 1264 + 1265 + enum { 1266 + IFLA_MCTP_UNSPEC, 1267 + IFLA_MCTP_NET, 1268 + __IFLA_MCTP_MAX, 1269 + }; 1270 + 1271 + #define IFLA_MCTP_MAX (__IFLA_MCTP_MAX - 1) 1272 + 1263 1273 #endif /* _UAPI_LINUX_IF_LINK_H */
+1
include/uapi/linux/mctp.h
··· 26 26 }; 27 27 28 28 #define MCTP_NET_ANY 0x0 29 + #define MCTP_NET_DEFAULT 0x0 29 30 30 31 #define MCTP_ADDR_NULL 0x00 31 32 #define MCTP_ADDR_ANY 0xff
+1 -1
net/mctp/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_MCTP) += mctp.o 3 - mctp-objs := af_mctp.o 3 + mctp-objs := af_mctp.o device.o
+8
net/mctp/af_mctp.c
··· 6 6 * Copyright (c) 2021 Google 7 7 */ 8 8 9 + #include <linux/if_arp.h> 9 10 #include <linux/net.h> 10 11 #include <linux/mctp.h> 11 12 #include <linux/module.h> 12 13 #include <linux/socket.h> 13 14 15 + #include <net/mctp.h> 16 + #include <net/mctpdevice.h> 14 17 #include <net/sock.h> 18 + 19 + /* socket implementation */ 15 20 16 21 struct mctp_sock { 17 22 struct sock sk; ··· 157 152 if (rc) 158 153 goto err_unreg_sock; 159 154 155 + mctp_device_init(); 156 + 160 157 return 0; 161 158 162 159 err_unreg_sock: ··· 169 162 170 163 static __exit void mctp_exit(void) 171 164 { 165 + mctp_device_exit(); 172 166 proto_unregister(&mctp_proto); 173 167 sock_unregister(PF_MCTP); 174 168 }
+414
net/mctp/device.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Management Component Transport Protocol (MCTP) - device implementation. 4 + * 5 + * Copyright (c) 2021 Code Construct 6 + * Copyright (c) 2021 Google 7 + */ 8 + 9 + #include <linux/if_link.h> 10 + #include <linux/mctp.h> 11 + #include <linux/netdevice.h> 12 + #include <linux/rcupdate.h> 13 + #include <linux/rtnetlink.h> 14 + 15 + #include <net/addrconf.h> 16 + #include <net/netlink.h> 17 + #include <net/mctp.h> 18 + #include <net/mctpdevice.h> 19 + #include <net/sock.h> 20 + 21 + struct mctp_dump_cb { 22 + int h; 23 + int idx; 24 + size_t a_idx; 25 + }; 26 + 27 + /* unlocked: caller must hold rcu_read_lock */ 28 + struct mctp_dev *__mctp_dev_get(const struct net_device *dev) 29 + { 30 + return rcu_dereference(dev->mctp_ptr); 31 + } 32 + 33 + struct mctp_dev *mctp_dev_get_rtnl(const struct net_device *dev) 34 + { 35 + return rtnl_dereference(dev->mctp_ptr); 36 + } 37 + 38 + static void mctp_dev_destroy(struct mctp_dev *mdev) 39 + { 40 + struct net_device *dev = mdev->dev; 41 + 42 + dev_put(dev); 43 + kfree_rcu(mdev, rcu); 44 + } 45 + 46 + static int mctp_fill_addrinfo(struct sk_buff *skb, struct netlink_callback *cb, 47 + struct mctp_dev *mdev, mctp_eid_t eid) 48 + { 49 + struct ifaddrmsg *hdr; 50 + struct nlmsghdr *nlh; 51 + 52 + nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 53 + RTM_NEWADDR, sizeof(*hdr), NLM_F_MULTI); 54 + if (!nlh) 55 + return -EMSGSIZE; 56 + 57 + hdr = nlmsg_data(nlh); 58 + hdr->ifa_family = AF_MCTP; 59 + hdr->ifa_prefixlen = 0; 60 + hdr->ifa_flags = 0; 61 + hdr->ifa_scope = 0; 62 + hdr->ifa_index = mdev->dev->ifindex; 63 + 64 + if (nla_put_u8(skb, IFA_LOCAL, eid)) 65 + goto cancel; 66 + 67 + if (nla_put_u8(skb, IFA_ADDRESS, eid)) 68 + goto cancel; 69 + 70 + nlmsg_end(skb, nlh); 71 + 72 + return 0; 73 + 74 + cancel: 75 + nlmsg_cancel(skb, nlh); 76 + return -EMSGSIZE; 77 + } 78 + 79 + static int mctp_dump_dev_addrinfo(struct mctp_dev *mdev, struct sk_buff *skb, 80 + struct netlink_callback *cb) 81 + { 82 + struct mctp_dump_cb *mcb = (void *)cb->ctx; 83 + int rc = 0; 84 + 85 + for (; mcb->a_idx < mdev->num_addrs; mcb->a_idx++) { 86 + rc = mctp_fill_addrinfo(skb, cb, mdev, mdev->addrs[mcb->a_idx]); 87 + if (rc < 0) 88 + break; 89 + } 90 + 91 + return rc; 92 + } 93 + 94 + static int mctp_dump_addrinfo(struct sk_buff *skb, struct netlink_callback *cb) 95 + { 96 + struct mctp_dump_cb *mcb = (void *)cb->ctx; 97 + struct net *net = sock_net(skb->sk); 98 + struct hlist_head *head; 99 + struct net_device *dev; 100 + struct ifaddrmsg *hdr; 101 + struct mctp_dev *mdev; 102 + int ifindex; 103 + int idx, rc; 104 + 105 + hdr = nlmsg_data(cb->nlh); 106 + // filter by ifindex if requested 107 + ifindex = hdr->ifa_index; 108 + 109 + rcu_read_lock(); 110 + for (; mcb->h < NETDEV_HASHENTRIES; mcb->h++, mcb->idx = 0) { 111 + idx = 0; 112 + head = &net->dev_index_head[mcb->h]; 113 + hlist_for_each_entry_rcu(dev, head, index_hlist) { 114 + if (idx >= mcb->idx && 115 + (ifindex == 0 || ifindex == dev->ifindex)) { 116 + mdev = __mctp_dev_get(dev); 117 + if (mdev) { 118 + rc = mctp_dump_dev_addrinfo(mdev, 119 + skb, cb); 120 + // Error indicates full buffer, this 121 + // callback will get retried. 122 + if (rc < 0) 123 + goto out; 124 + } 125 + } 126 + idx++; 127 + // reset for next iteration 128 + mcb->a_idx = 0; 129 + } 130 + } 131 + out: 132 + rcu_read_unlock(); 133 + mcb->idx = idx; 134 + 135 + return skb->len; 136 + } 137 + 138 + static const struct nla_policy ifa_mctp_policy[IFA_MAX + 1] = { 139 + [IFA_ADDRESS] = { .type = NLA_U8 }, 140 + [IFA_LOCAL] = { .type = NLA_U8 }, 141 + }; 142 + 143 + static int mctp_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, 144 + struct netlink_ext_ack *extack) 145 + { 146 + struct net *net = sock_net(skb->sk); 147 + struct nlattr *tb[IFA_MAX + 1]; 148 + struct net_device *dev; 149 + struct mctp_addr *addr; 150 + struct mctp_dev *mdev; 151 + struct ifaddrmsg *ifm; 152 + unsigned long flags; 153 + u8 *tmp_addrs; 154 + int rc; 155 + 156 + rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_mctp_policy, 157 + extack); 158 + if (rc < 0) 159 + return rc; 160 + 161 + ifm = nlmsg_data(nlh); 162 + 163 + if (tb[IFA_LOCAL]) 164 + addr = nla_data(tb[IFA_LOCAL]); 165 + else if (tb[IFA_ADDRESS]) 166 + addr = nla_data(tb[IFA_ADDRESS]); 167 + else 168 + return -EINVAL; 169 + 170 + /* find device */ 171 + dev = __dev_get_by_index(net, ifm->ifa_index); 172 + if (!dev) 173 + return -ENODEV; 174 + 175 + mdev = mctp_dev_get_rtnl(dev); 176 + if (!mdev) 177 + return -ENODEV; 178 + 179 + if (!mctp_address_ok(addr->s_addr)) 180 + return -EINVAL; 181 + 182 + /* Prevent duplicates. Under RTNL so don't need to lock for reading */ 183 + if (memchr(mdev->addrs, addr->s_addr, mdev->num_addrs)) 184 + return -EEXIST; 185 + 186 + tmp_addrs = kmalloc(mdev->num_addrs + 1, GFP_KERNEL); 187 + if (!tmp_addrs) 188 + return -ENOMEM; 189 + memcpy(tmp_addrs, mdev->addrs, mdev->num_addrs); 190 + tmp_addrs[mdev->num_addrs] = addr->s_addr; 191 + 192 + /* Lock to write */ 193 + spin_lock_irqsave(&mdev->addrs_lock, flags); 194 + mdev->num_addrs++; 195 + swap(mdev->addrs, tmp_addrs); 196 + spin_unlock_irqrestore(&mdev->addrs_lock, flags); 197 + 198 + kfree(tmp_addrs); 199 + 200 + return 0; 201 + } 202 + 203 + static int mctp_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, 204 + struct netlink_ext_ack *extack) 205 + { 206 + struct net *net = sock_net(skb->sk); 207 + struct nlattr *tb[IFA_MAX + 1]; 208 + struct net_device *dev; 209 + struct mctp_addr *addr; 210 + struct mctp_dev *mdev; 211 + struct ifaddrmsg *ifm; 212 + unsigned long flags; 213 + u8 *pos; 214 + int rc; 215 + 216 + rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_mctp_policy, 217 + extack); 218 + if (rc < 0) 219 + return rc; 220 + 221 + ifm = nlmsg_data(nlh); 222 + 223 + if (tb[IFA_LOCAL]) 224 + addr = nla_data(tb[IFA_LOCAL]); 225 + else if (tb[IFA_ADDRESS]) 226 + addr = nla_data(tb[IFA_ADDRESS]); 227 + else 228 + return -EINVAL; 229 + 230 + /* find device */ 231 + dev = __dev_get_by_index(net, ifm->ifa_index); 232 + if (!dev) 233 + return -ENODEV; 234 + 235 + mdev = mctp_dev_get_rtnl(dev); 236 + if (!mdev) 237 + return -ENODEV; 238 + 239 + pos = memchr(mdev->addrs, addr->s_addr, mdev->num_addrs); 240 + if (!pos) 241 + return -ENOENT; 242 + 243 + spin_lock_irqsave(&mdev->addrs_lock, flags); 244 + memmove(pos, pos + 1, mdev->num_addrs - 1 - (pos - mdev->addrs)); 245 + mdev->num_addrs--; 246 + spin_unlock_irqrestore(&mdev->addrs_lock, flags); 247 + 248 + return 0; 249 + } 250 + 251 + static struct mctp_dev *mctp_add_dev(struct net_device *dev) 252 + { 253 + struct mctp_dev *mdev; 254 + 255 + ASSERT_RTNL(); 256 + 257 + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 258 + if (!mdev) 259 + return ERR_PTR(-ENOMEM); 260 + 261 + spin_lock_init(&mdev->addrs_lock); 262 + 263 + mdev->net = MCTP_INITIAL_DEFAULT_NET; 264 + 265 + /* associate to net_device */ 266 + rcu_assign_pointer(dev->mctp_ptr, mdev); 267 + dev_hold(dev); 268 + mdev->dev = dev; 269 + 270 + return mdev; 271 + } 272 + 273 + static int mctp_fill_link_af(struct sk_buff *skb, 274 + const struct net_device *dev, u32 ext_filter_mask) 275 + { 276 + struct mctp_dev *mdev; 277 + 278 + mdev = mctp_dev_get_rtnl(dev); 279 + if (!mdev) 280 + return -ENODATA; 281 + if (nla_put_u32(skb, IFLA_MCTP_NET, mdev->net)) 282 + return -EMSGSIZE; 283 + return 0; 284 + } 285 + 286 + static size_t mctp_get_link_af_size(const struct net_device *dev, 287 + u32 ext_filter_mask) 288 + { 289 + struct mctp_dev *mdev; 290 + unsigned int ret; 291 + 292 + /* caller holds RCU */ 293 + mdev = __mctp_dev_get(dev); 294 + if (!mdev) 295 + return 0; 296 + ret = nla_total_size(4); /* IFLA_MCTP_NET */ 297 + return ret; 298 + } 299 + 300 + static const struct nla_policy ifla_af_mctp_policy[IFLA_MCTP_MAX + 1] = { 301 + [IFLA_MCTP_NET] = { .type = NLA_U32 }, 302 + }; 303 + 304 + static int mctp_set_link_af(struct net_device *dev, const struct nlattr *attr, 305 + struct netlink_ext_ack *extack) 306 + { 307 + struct nlattr *tb[IFLA_MCTP_MAX + 1]; 308 + struct mctp_dev *mdev; 309 + int rc; 310 + 311 + rc = nla_parse_nested(tb, IFLA_MCTP_MAX, attr, ifla_af_mctp_policy, 312 + NULL); 313 + if (rc) 314 + return rc; 315 + 316 + mdev = mctp_dev_get_rtnl(dev); 317 + if (!mdev) 318 + return 0; 319 + 320 + if (tb[IFLA_MCTP_NET]) 321 + WRITE_ONCE(mdev->net, nla_get_u32(tb[IFLA_MCTP_NET])); 322 + 323 + return 0; 324 + } 325 + 326 + static void mctp_unregister(struct net_device *dev) 327 + { 328 + struct mctp_dev *mdev; 329 + 330 + mdev = mctp_dev_get_rtnl(dev); 331 + 332 + if (!mdev) 333 + return; 334 + 335 + RCU_INIT_POINTER(mdev->dev->mctp_ptr, NULL); 336 + 337 + kfree(mdev->addrs); 338 + 339 + mctp_dev_destroy(mdev); 340 + } 341 + 342 + static int mctp_register(struct net_device *dev) 343 + { 344 + struct mctp_dev *mdev; 345 + 346 + /* Already registered? */ 347 + if (rtnl_dereference(dev->mctp_ptr)) 348 + return 0; 349 + 350 + /* only register specific types; MCTP-specific and loopback for now */ 351 + if (dev->type != ARPHRD_MCTP && dev->type != ARPHRD_LOOPBACK) 352 + return 0; 353 + 354 + mdev = mctp_add_dev(dev); 355 + if (IS_ERR(mdev)) 356 + return PTR_ERR(mdev); 357 + 358 + return 0; 359 + } 360 + 361 + static int mctp_dev_notify(struct notifier_block *this, unsigned long event, 362 + void *ptr) 363 + { 364 + struct net_device *dev = netdev_notifier_info_to_dev(ptr); 365 + int rc; 366 + 367 + switch (event) { 368 + case NETDEV_REGISTER: 369 + rc = mctp_register(dev); 370 + if (rc) 371 + return notifier_from_errno(rc); 372 + break; 373 + case NETDEV_UNREGISTER: 374 + mctp_unregister(dev); 375 + break; 376 + } 377 + 378 + return NOTIFY_OK; 379 + } 380 + 381 + static struct rtnl_af_ops mctp_af_ops = { 382 + .family = AF_MCTP, 383 + .fill_link_af = mctp_fill_link_af, 384 + .get_link_af_size = mctp_get_link_af_size, 385 + .set_link_af = mctp_set_link_af, 386 + }; 387 + 388 + static struct notifier_block mctp_dev_nb = { 389 + .notifier_call = mctp_dev_notify, 390 + .priority = ADDRCONF_NOTIFY_PRIORITY, 391 + }; 392 + 393 + void __init mctp_device_init(void) 394 + { 395 + register_netdevice_notifier(&mctp_dev_nb); 396 + 397 + rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_GETADDR, 398 + NULL, mctp_dump_addrinfo, 0); 399 + rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_NEWADDR, 400 + mctp_rtm_newaddr, NULL, 0); 401 + rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_DELADDR, 402 + mctp_rtm_deladdr, NULL, 0); 403 + rtnl_af_register(&mctp_af_ops); 404 + } 405 + 406 + void __exit mctp_device_exit(void) 407 + { 408 + rtnl_af_unregister(&mctp_af_ops); 409 + rtnl_unregister(PF_MCTP, RTM_DELADDR); 410 + rtnl_unregister(PF_MCTP, RTM_NEWADDR); 411 + rtnl_unregister(PF_MCTP, RTM_GETADDR); 412 + 413 + unregister_netdevice_notifier(&mctp_dev_nb); 414 + }