/* * Dump information about all ports, in response to GETLINK */ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); struct net_device *dev; int idx; idx = 0; rcu_read_lock(); for_each_netdev_rcu(net, dev) { struct net_bridge_port *port = br_port_get_rcu(dev); /* not a bridge port */ if (!port || idx < cb->args[0]) goto skip; if (br_fill_ifinfo(skb, port, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI) < 0) break; skip: ++idx; } rcu_read_unlock(); cb->args[0] = idx; return skb->len; }
/* * Notify listeners of a change in port information */ void br_ifinfo_notify(int event, struct net_bridge_port *port) { struct net *net; struct sk_buff *skb; int err = -ENOBUFS; if (!port) return; net = dev_net(port->dev); br_debug(port->br, "port %u(%s) event %d\n", (unsigned int)port->port_no, port->dev->name, event); skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = br_fill_ifinfo(skb, port, 0, 0, event, 0, 0, port->dev); if (err < 0) { /* -EMSGSIZE implies BUG in br_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); return; errout: if (err < 0) rtnl_set_sk_err(net, RTNLGRP_LINK, err); }
/* * Dump information about all ports, in response to GETLINK */ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net *net = sock_net(skb->sk); struct net_device *dev; int idx; idx = 0; for_each_netdev(net, dev) { /* not a bridge port */ if (!br_port_exists(dev) || idx < cb->args[0]) goto skip; if (br_fill_ifinfo(skb, br_port_get(dev), NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI) < 0) break; skip: ++idx; } cb->args[0] = idx; return skb->len; }
/* * Dump information about all ports, in response to GETLINK */ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev) { int err = 0; struct net_bridge_port *port = br_port_get_rcu(dev); /* not a bridge port */ if (!port) goto out; err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI); out: return err; }
/* * Dump information about all ports, in response to GETLINK */ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u32 filter_mask) { int err = 0; struct net_bridge_port *port = br_port_get_rcu(dev); /* not a bridge port and */ if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN)) goto out; err = br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, NLM_F_MULTI, filter_mask, dev); out: return err; }
/* * Notify listeners of a change in port information */ void br_ifinfo_notify(int event, struct net_bridge_port *port) { struct sk_buff *skb; int err = -ENOBUFS; pr_debug("bridge notify event=%d\n", event); skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = br_fill_ifinfo(skb, port, 0, 0, event, 0); /* failure implies BUG in br_nlmsg_size() */ BUG_ON(err < 0); err = rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); errout: if (err < 0) rtnl_set_sk_err(RTNLGRP_LINK, err); }
/* * Notify listeners of a change in port information */ void br_ifinfo_notify(int event, struct net_bridge_port *port) { struct net *net = dev_net(port->dev); struct sk_buff *skb; int err = -ENOBUFS; pr_debug("bridge notify event=%d\n", event); skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; err = br_fill_ifinfo(skb, port, 0, 0, event, 0); if (err < 0) { /* -EMSGSIZE implies BUG in br_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); kfree_skb(skb); goto errout; } err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); errout: if (err < 0) rtnl_set_sk_err(net, RTNLGRP_LINK, err); }
/* * Dump information about all ports, in response to GETLINK */ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { struct net_device *dev; int idx; read_lock(&dev_base_lock); for (dev = dev_base, idx = 0; dev; dev = dev->next) { /* not a bridge port */ if (dev->br_port == NULL || idx < cb->args[0]) goto skip; if (br_fill_ifinfo(skb, dev->br_port, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI) < 0) break; skip: ++idx; } read_unlock(&dev_base_lock); cb->args[0] = idx; return skb->len; }