1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/netdevice.h> 4 #include <linux/notifier.h> 5 #include <linux/rtnetlink.h> 6 #include <net/net_namespace.h> 7 #include <net/sock.h> 8 9 #include "netdev-genl-gen.h" 10 11 static int 12 netdev_nl_dev_fill(struct net_device *netdev, struct sk_buff *rsp, 13 u32 portid, u32 seq, int flags, u32 cmd) 14 { 15 void *hdr; 16 17 hdr = genlmsg_put(rsp, portid, seq, &netdev_nl_family, flags, cmd); 18 if (!hdr) 19 return -EMSGSIZE; 20 21 if (nla_put_u32(rsp, NETDEV_A_DEV_IFINDEX, netdev->ifindex) || 22 nla_put_u64_64bit(rsp, NETDEV_A_DEV_XDP_FEATURES, 23 netdev->xdp_features, NETDEV_A_DEV_PAD)) { 24 genlmsg_cancel(rsp, hdr); 25 return -EINVAL; 26 } 27 28 genlmsg_end(rsp, hdr); 29 30 return 0; 31 } 32 33 static void 34 netdev_genl_dev_notify(struct net_device *netdev, int cmd) 35 { 36 struct sk_buff *ntf; 37 38 if (!genl_has_listeners(&netdev_nl_family, dev_net(netdev), 39 NETDEV_NLGRP_MGMT)) 40 return; 41 42 ntf = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 43 if (!ntf) 44 return; 45 46 if (netdev_nl_dev_fill(netdev, ntf, 0, 0, 0, cmd)) { 47 nlmsg_free(ntf); 48 return; 49 } 50 51 genlmsg_multicast_netns(&netdev_nl_family, dev_net(netdev), ntf, 52 0, NETDEV_NLGRP_MGMT, GFP_KERNEL); 53 } 54 55 int netdev_nl_dev_get_doit(struct sk_buff *skb, struct genl_info *info) 56 { 57 struct net_device *netdev; 58 struct sk_buff *rsp; 59 u32 ifindex; 60 int err; 61 62 if (GENL_REQ_ATTR_CHECK(info, NETDEV_A_DEV_IFINDEX)) 63 return -EINVAL; 64 65 ifindex = nla_get_u32(info->attrs[NETDEV_A_DEV_IFINDEX]); 66 67 rsp = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); 68 if (!rsp) 69 return -ENOMEM; 70 71 rtnl_lock(); 72 73 netdev = __dev_get_by_index(genl_info_net(info), ifindex); 74 if (netdev) 75 err = netdev_nl_dev_fill(netdev, rsp, info->snd_portid, 76 info->snd_seq, 0, info->genlhdr->cmd); 77 else 78 err = -ENODEV; 79 80 rtnl_unlock(); 81 82 if (err) 83 goto err_free_msg; 84 85 return genlmsg_reply(rsp, info); 86 87 err_free_msg: 88 nlmsg_free(rsp); 89 return err; 90 } 91 92 int netdev_nl_dev_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) 93 { 94 struct net *net = sock_net(skb->sk); 95 struct net_device *netdev; 96 int idx = 0, s_idx; 97 int h, s_h; 98 int err; 99 100 s_h = cb->args[0]; 101 s_idx = cb->args[1]; 102 103 rtnl_lock(); 104 105 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { 106 struct hlist_head *head; 107 108 idx = 0; 109 head = &net->dev_index_head[h]; 110 hlist_for_each_entry(netdev, head, index_hlist) { 111 if (idx < s_idx) 112 goto cont; 113 err = netdev_nl_dev_fill(netdev, skb, 114 NETLINK_CB(cb->skb).portid, 115 cb->nlh->nlmsg_seq, 0, 116 NETDEV_CMD_DEV_GET); 117 if (err < 0) 118 break; 119 cont: 120 idx++; 121 } 122 } 123 124 rtnl_unlock(); 125 126 if (err != -EMSGSIZE) 127 return err; 128 129 cb->args[1] = idx; 130 cb->args[0] = h; 131 cb->seq = net->dev_base_seq; 132 133 return skb->len; 134 } 135 136 static int netdev_genl_netdevice_event(struct notifier_block *nb, 137 unsigned long event, void *ptr) 138 { 139 struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 140 141 switch (event) { 142 case NETDEV_REGISTER: 143 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_ADD_NTF); 144 break; 145 case NETDEV_UNREGISTER: 146 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_DEL_NTF); 147 break; 148 case NETDEV_XDP_FEAT_CHANGE: 149 netdev_genl_dev_notify(netdev, NETDEV_CMD_DEV_CHANGE_NTF); 150 break; 151 } 152 153 return NOTIFY_OK; 154 } 155 156 static struct notifier_block netdev_genl_nb = { 157 .notifier_call = netdev_genl_netdevice_event, 158 }; 159 160 static int __init netdev_genl_init(void) 161 { 162 int err; 163 164 err = register_netdevice_notifier(&netdev_genl_nb); 165 if (err) 166 return err; 167 168 err = genl_register_family(&netdev_nl_family); 169 if (err) 170 goto err_unreg_ntf; 171 172 return 0; 173 174 err_unreg_ntf: 175 unregister_netdevice_notifier(&netdev_genl_nb); 176 return err; 177 } 178 179 subsys_initcall(netdev_genl_init); 180