diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
commit | 59223edaa18759982db0a8aced0e77457d10c68e (patch) | |
tree | 89354903b01fa0a447bffeefe00df3044495db2e /net/ipv4/fib_rules.c | |
parent | db7d4daea91e105e3859cf461d7e53b9b77454b2 (diff) |
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'net/ipv4/fib_rules.c')
-rw-r--r-- | net/ipv4/fib_rules.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 868c44c31..97074198e 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: policy rules. * - * Version: $Id: fib_rules.c,v 1.9 1999/03/25 10:04:23 davem Exp $ + * Version: $Id: fib_rules.c,v 1.11 1999/06/09 10:10:47 davem Exp $ * * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * @@ -79,12 +79,14 @@ static struct fib_rule main_rule = { &default_rule, 0x7FFE, RT_TABLE_MAIN, RTN_U static struct fib_rule local_rule = { &main_rule, 0, RT_TABLE_LOCAL, RTN_UNICAST, }; static struct fib_rule *fib_rules = &local_rule; +static rwlock_t fib_rules_lock = RW_LOCK_UNLOCKED; int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { struct rtattr **rta = arg; struct rtmsg *rtm = NLMSG_DATA(nlh); struct fib_rule *r, **rp; + int err = -ESRCH; for (rp=&fib_rules; (r=*rp) != NULL; rp=&r->r_next) { if ((!rta[RTA_SRC-1] || memcmp(RTA_DATA(rta[RTA_SRC-1]), &r->r_src, 4) == 0) && @@ -99,18 +101,20 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) && (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) && (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) { + err = -EPERM; if (r == &local_rule) - return -EPERM; + break; + write_lock_bh(&fib_rules_lock); *rp = r->r_next; - synchronize_bh(); - + write_unlock_bh(&fib_rules_lock); if (r != &default_rule && r != &main_rule) kfree(r); - return 0; + err = 0; + break; } } - return -ESRCH; + return err; } /* Allocate new unique table id */ @@ -205,7 +209,9 @@ int inet_rtm_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } new_r->r_next = r; + write_lock_bh(&fib_rules_lock); *rp = new_r; + write_unlock_bh(&fib_rules_lock); return 0; } @@ -250,8 +256,11 @@ static void fib_rules_detach(struct device *dev) struct fib_rule *r; for (r=fib_rules; r; r=r->r_next) { - if (r->r_ifindex == dev->ifindex) + if (r->r_ifindex == dev->ifindex) { + write_lock_bh(&fib_rules_lock); r->r_ifindex = -1; + write_unlock_bh(&fib_rules_lock); + } } } @@ -260,8 +269,11 @@ static void fib_rules_attach(struct device *dev) struct fib_rule *r; for (r=fib_rules; r; r=r->r_next) { - if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) + if (r->r_ifindex == -1 && strcmp(dev->name, r->r_ifname) == 0) { + write_lock_bh(&fib_rules_lock); r->r_ifindex = dev->ifindex; + write_unlock_bh(&fib_rules_lock); + } } } @@ -275,6 +287,7 @@ int fib_lookup(const struct rt_key *key, struct fib_result *res) u32 saddr = key->src; FRprintk("Lookup: %08x <- %08x ", key->dst, key->src); + read_lock(&fib_rules_lock); for (r = fib_rules; r; r=r->r_next) { if (((saddr^r->r_src) & r->r_srcmask) || ((daddr^r->r_dst) & r->r_dstmask) || @@ -294,11 +307,14 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action); policy = r; break; case RTN_UNREACHABLE: + read_unlock(&fib_rules_lock); return -ENETUNREACH; default: case RTN_BLACKHOLE: + read_unlock(&fib_rules_lock); return -EINVAL; case RTN_PROHIBIT: + read_unlock(&fib_rules_lock); return -EACCES; } @@ -308,12 +324,16 @@ FRprintk("tb %d r %d ", r->r_table, r->r_action); if (err == 0) { FRprintk("ok\n"); res->r = policy; + read_unlock(&fib_rules_lock); return 0; } - if (err < 0 && err != -EAGAIN) + if (err < 0 && err != -EAGAIN) { + read_unlock(&fib_rules_lock); return err; + } } FRprintk("FAILURE\n"); + read_unlock(&fib_rules_lock); return -ENETUNREACH; } @@ -400,12 +420,14 @@ int inet_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) int s_idx = cb->args[0]; struct fib_rule *r; + read_lock(&fib_rules_lock); for (r=fib_rules, idx=0; r; r = r->r_next, idx++) { if (idx < s_idx) continue; if (inet_fill_rule(skb, r, cb) < 0) break; } + read_unlock(&fib_rules_lock); cb->args[0] = idx; return skb->len; |