X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fcore%2Fneighbour.c;h=512eed91785dc5dbab2de12a4603473dddc6b791;hb=9a32144e9d7b4e21341174b1a83b82a82353be86;hp=0ab1987b9348505b1ca0e6e6c155b3960a68b75c;hpb=2fd8507d14ef7af3ae05316b3277044cf6daa381;p=linux-2.6 diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0ab1987b93..512eed9178 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -63,7 +63,7 @@ void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); static struct neigh_table *neigh_tables; #ifdef CONFIG_PROC_FS -static struct file_operations neigh_stat_seq_fops; +static const struct file_operations neigh_stat_seq_fops; #endif /* @@ -251,12 +251,10 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl) goto out_entries; } - n = kmem_cache_alloc(tbl->kmem_cachep, GFP_ATOMIC); + n = kmem_cache_zalloc(tbl->kmem_cachep, GFP_ATOMIC); if (!n) goto out_entries; - memset(n, 0, tbl->entry_size); - skb_queue_head_init(&n->arp_queue); rwlock_init(&n->lock); n->updated = n->used = now; @@ -345,7 +343,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, struct neighbour *n; int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, dev); - + NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); @@ -577,9 +575,10 @@ void neigh_destroy(struct neighbour *neigh) while ((hh = neigh->hh) != NULL) { neigh->hh = hh->hh_next; hh->hh_next = NULL; - write_lock_bh(&hh->hh_lock); + + write_seqlock_bh(&hh->hh_lock); hh->hh_output = neigh_blackhole; - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); if (atomic_dec_and_test(&hh->hh_refcnt)) kfree(hh); } @@ -686,16 +685,19 @@ next_elt: np = &n->next; } - /* Cycle through all hash buckets every base_reachable_time/2 ticks. - * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 - * base_reachable_time. + /* Cycle through all hash buckets every base_reachable_time/2 ticks. + * ARP entry timeouts range from 1/2 base_reachable_time to 3/2 + * base_reachable_time. */ expire = tbl->parms.base_reachable_time >> 1; expire /= (tbl->hash_mask + 1); if (!expire) expire = 1; - mod_timer(&tbl->gc_timer, now + expire); + if (expire>HZ) + mod_timer(&tbl->gc_timer, round_jiffies(now + expire)); + else + mod_timer(&tbl->gc_timer, now + expire); write_unlock(&tbl->lock); } @@ -740,7 +742,7 @@ static void neigh_timer_handler(unsigned long arg) } if (state & NUD_REACHABLE) { - if (time_before_eq(now, + if (time_before_eq(now, neigh->confirmed + neigh->parms->reachable_time)) { NEIGH_PRINTK2("neigh %p is still alive.\n", neigh); next = neigh->confirmed + neigh->parms->reachable_time; @@ -759,7 +761,7 @@ static void neigh_timer_handler(unsigned long arg) notify = 1; } } else if (state & NUD_DELAY) { - if (time_before_eq(now, + if (time_before_eq(now, neigh->confirmed + neigh->parms->delay_probe_time)) { NEIGH_PRINTK2("neigh %p is now reachable.\n", neigh); neigh->nud_state = NUD_REACHABLE; @@ -845,7 +847,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) goto out_unlock_bh; now = jiffies; - + if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { if (neigh->parms->mcast_probes + neigh->parms->app_probes) { atomic_set(&neigh->probes, neigh->parms->ucast_probes); @@ -897,9 +899,9 @@ static void neigh_update_hhs(struct neighbour *neigh) if (update) { for (hh = neigh->hh; hh; hh = hh->hh_next) { - write_lock_bh(&hh->hh_lock); + write_seqlock_bh(&hh->hh_lock); update(hh, neigh->dev, neigh->ha); - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); } } } @@ -913,13 +915,13 @@ static void neigh_update_hhs(struct neighbour *neigh) NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr, if it is different. NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected" - lladdr instead of overriding it + lladdr instead of overriding it if it is different. It also allows to retain current state if lladdr is unchanged. NEIGH_UPDATE_F_ADMIN means that the change is administrative. - NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing + NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing NTF_ROUTER flag. NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as a router. @@ -942,7 +944,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, old = neigh->nud_state; err = -EPERM; - if (!(flags & NEIGH_UPDATE_F_ADMIN) && + if (!(flags & NEIGH_UPDATE_F_ADMIN) && (old & (NUD_NOARP | NUD_PERMANENT))) goto out; @@ -966,7 +968,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, - compare new & old - if they are different, check override flag */ - if ((old & NUD_VALID) && + if ((old & NUD_VALID) && !memcmp(lladdr, neigh->ha, dev->addr_len)) lladdr = neigh->ha; } else { @@ -1010,8 +1012,8 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, neigh_del_timer(neigh); if (new & NUD_IN_TIMER) { neigh_hold(neigh); - neigh_add_timer(neigh, (jiffies + - ((new & NUD_REACHABLE) ? + neigh_add_timer(neigh, (jiffies + + ((new & NUD_REACHABLE) ? neigh->parms->reachable_time : 0))); } @@ -1073,7 +1075,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl, struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev, lladdr || !dev->addr_len); if (neigh) - neigh_update(neigh, lladdr, NUD_STALE, + neigh_update(neigh, lladdr, NUD_STALE, NEIGH_UPDATE_F_OVERRIDE); return neigh; } @@ -1089,7 +1091,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, break; if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { - rwlock_init(&hh->hh_lock); + seqlock_init(&hh->hh_lock); hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; @@ -1125,7 +1127,7 @@ int neigh_compat_output(struct sk_buff *skb) if (dev->hard_header && dev->hard_header(skb, dev, ntohs(skb->protocol), NULL, NULL, - skb->len) < 0 && + skb->len) < 0 && dev->rebuild_header(skb)) return 0; @@ -1345,10 +1347,10 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) tbl->stats = alloc_percpu(struct neigh_statistics); if (!tbl->stats) panic("cannot create neighbour cache statistics"); - + #ifdef CONFIG_PROC_FS tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat); - if (!tbl->pde) + if (!tbl->pde) panic("cannot create neighbour proc dir entry"); tbl->pde->proc_fops = &neigh_stat_seq_fops; tbl->pde->data = tbl; @@ -1563,7 +1565,7 @@ int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) err = -ENOENT; goto out_dev_put; } - + neigh = __neigh_lookup_errno(tbl, dst, dev); if (IS_ERR(neigh)) { err = PTR_ERR(neigh); @@ -1636,7 +1638,7 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); if (nlh == NULL) - return -ENOBUFS; + return -EMSGSIZE; ndtmsg = nlmsg_data(nlh); @@ -1705,7 +1707,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, nla_put_failure: read_unlock_bh(&tbl->lock); - return nlmsg_cancel(skb, nlh); + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } static int neightbl_fill_param_info(struct sk_buff *skb, @@ -1719,7 +1722,7 @@ static int neightbl_fill_param_info(struct sk_buff *skb, nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); if (nlh == NULL) - return -ENOBUFS; + return -EMSGSIZE; ndtmsg = nlmsg_data(nlh); @@ -1736,14 +1739,15 @@ static int neightbl_fill_param_info(struct sk_buff *skb, return nlmsg_end(skb, nlh); errout: read_unlock_bh(&tbl->lock); - return nlmsg_cancel(skb, nlh); + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } - + static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, int ifindex) { struct neigh_parms *p; - + for (p = &tbl->parms; p; p = p->next) if ((p->dev && p->dev->ifindex == ifindex) || (!p->dev && !ifindex)) @@ -1809,7 +1813,7 @@ int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) goto errout_locked; } - /* + /* * We acquire tbl->lock to be nice to the periodic timers and * make sure they always see a consistent set of values. */ @@ -1954,7 +1958,7 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh, nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); if (nlh == NULL) - return -ENOBUFS; + return -EMSGSIZE; ndm = nlmsg_data(nlh); ndm->ndm_family = neigh->ops->family; @@ -1986,7 +1990,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh, return nlmsg_end(skb, nlh); nla_put_failure: - return nlmsg_cancel(skb, nlh); + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; } @@ -2316,7 +2321,7 @@ static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; @@ -2398,7 +2403,7 @@ static int neigh_stat_seq_open(struct inode *inode, struct file *file) return ret; }; -static struct file_operations neigh_stat_seq_fops = { +static const struct file_operations neigh_stat_seq_fops = { .owner = THIS_MODULE, .open = neigh_stat_seq_open, .read = seq_read, @@ -2428,9 +2433,12 @@ static void __neigh_notify(struct neighbour *n, int type, int flags) goto errout; err = neigh_fill_info(skb, n, 0, 0, type, flags); - /* failure implies BUG in neigh_nlmsg_size() */ - BUG_ON(err < 0); - + if (err < 0) { + /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */ + WARN_ON(err == -EMSGSIZE); + kfree_skb(skb); + goto errout; + } err = rtnl_notify(skb, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); errout: if (err < 0) @@ -2621,7 +2629,7 @@ static struct neigh_sysctl_table { }; int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, - int p_id, int pdev_id, char *p_name, + int p_id, int pdev_id, char *p_name, proc_handler *handler, ctl_handler *strategy) { struct neigh_sysctl_table *t = kmemdup(&neigh_sysctl_template, @@ -2653,7 +2661,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, t->neigh_vars[14].procname = NULL; t->neigh_vars[15].procname = NULL; } else { - dev_name_source = t->neigh_dev[0].procname; + dev_name_source = t->neigh_dev[0].procname; t->neigh_vars[12].data = (int *)(p + 1); t->neigh_vars[13].data = (int *)(p + 1) + 1; t->neigh_vars[14].data = (int *)(p + 1) + 2; @@ -2688,7 +2696,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, goto free; } - t->neigh_dev[0].procname = dev_name; + t->neigh_dev[0].procname = dev_name; t->neigh_neigh_dir[0].ctl_name = pdev_id;