aboutsummaryrefslogtreecommitdiff
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_device.c3
-rw-r--r--net/bridge/br_fdb.c128
-rw-r--r--net/bridge/br_netlink.c12
-rw-r--r--net/bridge/br_private.h15
4 files changed, 46 insertions, 112 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ba829de8442..d6e5929458b 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -317,6 +317,9 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_add_slave = br_add_slave,
.ndo_del_slave = br_del_slave,
.ndo_fix_features = br_fix_features,
+ .ndo_fdb_add = br_fdb_add,
+ .ndo_fdb_del = br_fdb_delete,
+ .ndo_fdb_dump = br_fdb_dump,
};
static void br_dev_free(struct net_device *dev)
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 80dbce4974c..5945c54bc2d 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -535,44 +535,38 @@ errout:
}
/* Dump information about entries, in response to GETNEIGH */
-int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
+int br_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ int idx)
{
- struct net *net = sock_net(skb->sk);
- struct net_device *dev;
- int idx = 0;
-
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
- struct net_bridge *br = netdev_priv(dev);
- int i;
-
- if (!(dev->priv_flags & IFF_EBRIDGE))
- continue;
+ struct net_bridge *br = netdev_priv(dev);
+ int i;
- for (i = 0; i < BR_HASH_SIZE; i++) {
- struct hlist_node *h;
- struct net_bridge_fdb_entry *f;
+ if (!(dev->priv_flags & IFF_EBRIDGE))
+ goto out;
- hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
- if (idx < cb->args[0])
- goto skip;
+ for (i = 0; i < BR_HASH_SIZE; i++) {
+ struct hlist_node *h;
+ struct net_bridge_fdb_entry *f;
- if (fdb_fill_info(skb, br, f,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq,
- RTM_NEWNEIGH,
- NLM_F_MULTI) < 0)
- break;
+ hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) {
+ if (idx < cb->args[0])
+ goto skip;
+
+ if (fdb_fill_info(skb, br, f,
+ NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ RTM_NEWNEIGH,
+ NLM_F_MULTI) < 0)
+ break;
skip:
- ++idx;
- }
+ ++idx;
}
}
- rcu_read_unlock();
-
- cb->args[0] = idx;
- return skb->len;
+out:
+ return idx;
}
/* Update (create or replace) forwarding database entry */
@@ -614,43 +608,11 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
}
/* Add new permanent fdb entry with RTM_NEWNEIGH */
-int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+int br_fdb_add(struct ndmsg *ndm, struct net_device *dev,
+ unsigned char *addr, u16 nlh_flags)
{
- struct net *net = sock_net(skb->sk);
- struct ndmsg *ndm;
- struct nlattr *tb[NDA_MAX+1];
- struct net_device *dev;
struct net_bridge_port *p;
- const __u8 *addr;
- int err;
-
- ASSERT_RTNL();
- err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
- if (err < 0)
- return err;
-
- ndm = nlmsg_data(nlh);
- if (ndm->ndm_ifindex == 0) {
- pr_info("bridge: RTM_NEWNEIGH with invalid ifindex\n");
- return -EINVAL;
- }
-
- dev = __dev_get_by_index(net, ndm->ndm_ifindex);
- if (dev == NULL) {
- pr_info("bridge: RTM_NEWNEIGH with unknown ifindex\n");
- return -ENODEV;
- }
-
- if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) {
- pr_info("bridge: RTM_NEWNEIGH with invalid address\n");
- return -EINVAL;
- }
-
- addr = nla_data(tb[NDA_LLADDR]);
- if (!is_valid_ether_addr(addr)) {
- pr_info("bridge: RTM_NEWNEIGH with invalid ether address\n");
- return -EINVAL;
- }
+ int err = 0;
if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
@@ -670,14 +632,14 @@ int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
rcu_read_unlock();
} else {
spin_lock_bh(&p->br->hash_lock);
- err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
+ err = fdb_add_entry(p, addr, ndm->ndm_state, nlh_flags);
spin_unlock_bh(&p->br->hash_lock);
}
return err;
}
-static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
+static int fdb_delete_by_addr(struct net_bridge_port *p, u8 *addr)
{
struct net_bridge *br = p->br;
struct hlist_head *head = &br->hash[br_mac_hash(addr)];
@@ -692,40 +654,12 @@ static int fdb_delete_by_addr(struct net_bridge_port *p, const u8 *addr)
}
/* Remove neighbor entry with RTM_DELNEIGH */
-int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+int br_fdb_delete(struct ndmsg *ndm, struct net_device *dev,
+ unsigned char *addr)
{
- struct net *net = sock_net(skb->sk);
- struct ndmsg *ndm;
struct net_bridge_port *p;
- struct nlattr *llattr;
- const __u8 *addr;
- struct net_device *dev;
int err;
- ASSERT_RTNL();
- if (nlmsg_len(nlh) < sizeof(*ndm))
- return -EINVAL;
-
- ndm = nlmsg_data(nlh);
- if (ndm->ndm_ifindex == 0) {
- pr_info("bridge: RTM_DELNEIGH with invalid ifindex\n");
- return -EINVAL;
- }
-
- dev = __dev_get_by_index(net, ndm->ndm_ifindex);
- if (dev == NULL) {
- pr_info("bridge: RTM_DELNEIGH with unknown ifindex\n");
- return -ENODEV;
- }
-
- llattr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_LLADDR);
- if (llattr == NULL || nla_len(llattr) != ETH_ALEN) {
- pr_info("bridge: RTM_DELNEIGH with invalid address\n");
- return -EINVAL;
- }
-
- addr = nla_data(llattr);
-
p = br_port_get_rtnl(dev);
if (p == NULL) {
pr_info("bridge: RTM_DELNEIGH %s not a bridge port\n",
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index df38108f697..2080485515f 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -232,18 +232,6 @@ int __init br_netlink_init(void)
br_rtm_setlink, NULL, NULL);
if (err)
goto err3;
- err = __rtnl_register(PF_BRIDGE, RTM_NEWNEIGH,
- br_fdb_add, NULL, NULL);
- if (err)
- goto err3;
- err = __rtnl_register(PF_BRIDGE, RTM_DELNEIGH,
- br_fdb_delete, NULL, NULL);
- if (err)
- goto err3;
- err = __rtnl_register(PF_BRIDGE, RTM_GETNEIGH,
- NULL, br_fdb_dump, NULL);
- if (err)
- goto err3;
return 0;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f8ffd8c4905..1a8ad4fb9a6 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -360,9 +360,18 @@ extern int br_fdb_insert(struct net_bridge *br,
extern void br_fdb_update(struct net_bridge *br,
struct net_bridge_port *source,
const unsigned char *addr);
-extern int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb);
-extern int br_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
-extern int br_fdb_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg);
+
+extern int br_fdb_delete(struct ndmsg *ndm,
+ struct net_device *dev,
+ unsigned char *addr);
+extern int br_fdb_add(struct ndmsg *nlh,
+ struct net_device *dev,
+ unsigned char *addr,
+ u16 nlh_flags);
+extern int br_fdb_dump(struct sk_buff *skb,
+ struct netlink_callback *cb,
+ struct net_device *dev,
+ int idx);
/* br_forward.c */
extern void br_deliver(const struct net_bridge_port *to,