X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fdecnet%2Fdn_neigh.c;h=dc48de88b9b3b19543708f0f6d3c5706ac4d7a78;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=ab64b850c12b3ff9df5339808796fbb1e56fcbd5;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index ab64b850c..dc48de88b 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -121,26 +123,32 @@ struct neigh_table dn_neigh_table = { static u32 dn_neigh_hash(const void *pkey, const struct net_device *dev) { - u32 hash_val; - - hash_val = *(dn_address *)pkey; - hash_val ^= (hash_val >> 10); - hash_val ^= (hash_val >> 3); - - return hash_val & NEIGH_HASHMASK; + return jhash_2words(*(dn_address *)pkey, 0, dn_neigh_table.hash_rnd); } static int dn_neigh_construct(struct neighbour *neigh) { struct net_device *dev = neigh->dev; struct dn_neigh *dn = (struct dn_neigh *)neigh; - struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; + struct dn_dev *dn_db; + struct neigh_parms *parms; - if (dn_db == NULL) + rcu_read_lock(); + dn_db = rcu_dereference(dev->dn_ptr); + if (dn_db == NULL) { + rcu_read_unlock(); return -EINVAL; + } - if (dn_db->neigh_parms) - neigh->parms = dn_db->neigh_parms; + parms = dn_db->neigh_parms; + if (!parms) { + rcu_read_unlock(); + return -EINVAL; + } + + __neigh_parms_put(neigh->parms); + neigh->parms = neigh_parms_clone(parms); + rcu_read_unlock(); if (dn_db->use_long) neigh->ops = &dn_long_ops; @@ -346,27 +354,6 @@ static int dn_phase3_output(struct sk_buff *skb) * basically does a neigh_lookup(), but without comparing the device * field. This is required for the On-Ethernet cache */ -struct neighbour *dn_neigh_lookup(struct neigh_table *tbl, const void *ptr) -{ - struct neighbour *neigh; - u32 hash_val; - - hash_val = tbl->hash(ptr, NULL); - - read_lock_bh(&tbl->lock); - for(neigh = tbl->hash_buckets[hash_val]; neigh != NULL; neigh = neigh->next) { - if (memcmp(neigh->primary_key, ptr, tbl->key_len) == 0) { - atomic_inc(&neigh->refcnt); - read_unlock_bh(&tbl->lock); - return neigh; - } - } - read_unlock_bh(&tbl->lock); - - return NULL; -} - - /* * Any traffic on a pointopoint link causes the timer to be reset * for the entry in the neighbour table. @@ -412,7 +399,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) neigh->updated = jiffies; if (neigh->dev->type == ARPHRD_ETHER) - memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN); + memcpy(neigh->ha, ð_hdr(skb)->h_source, ETH_ALEN); dn->blksize = dn_ntohs(msg->blksize); dn->priority = msg->priority; @@ -468,7 +455,7 @@ int dn_neigh_endnode_hello(struct sk_buff *skb) neigh->updated = jiffies; if (neigh->dev->type == ARPHRD_ETHER) - memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN); + memcpy(neigh->ha, ð_hdr(skb)->h_source, ETH_ALEN); dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2); dn->blksize = dn_ntohs(msg->blksize); dn->priority = 0; @@ -501,141 +488,66 @@ static char *dn_find_slot(char *base, int max, int priority) return (*min < priority) ? (min - 6) : NULL; } -int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) -{ - int t = 0; - int i; - struct neighbour *neigh; - struct dn_neigh *dn; - struct neigh_table *tbl = &dn_neigh_table; - unsigned char *rs = ptr; - struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr; - - read_lock_bh(&tbl->lock); - - for(i = 0; i < NEIGH_HASHMASK; i++) { - for(neigh = tbl->hash_buckets[i]; neigh != NULL; neigh = neigh->next) { - if (neigh->dev != dev) - continue; - dn = (struct dn_neigh *)neigh; - if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) - continue; - if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2)) - continue; - if (t == n) - rs = dn_find_slot(ptr, n, dn->priority); - else - t++; - if (rs == NULL) - continue; - dn_dn2eth(rs, dn->addr); - rs += 6; - *rs = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0; - *rs |= dn->priority; - rs++; - } - } - - read_unlock_bh(&tbl->lock); - - return t; -} - - -#ifdef CONFIG_PROC_FS - -struct dn_neigh_iter_state { - int bucket; +struct elist_cb_state { + struct net_device *dev; + unsigned char *ptr; + unsigned char *rs; + int t, n; }; -static struct neighbour *neigh_get_first(struct seq_file *seq) +static void neigh_elist_cb(struct neighbour *neigh, void *_info) { - struct dn_neigh_iter_state *state = seq->private; - struct neighbour *n = NULL; - - for(state->bucket = 0; - state->bucket <= NEIGH_HASHMASK; - ++state->bucket) { - n = dn_neigh_table.hash_buckets[state->bucket]; - if (n) - break; - } - - return n; -} - -static struct neighbour *neigh_get_next(struct seq_file *seq, - struct neighbour *n) -{ - struct dn_neigh_iter_state *state = seq->private; + struct elist_cb_state *s = _info; + struct dn_dev *dn_db; + struct dn_neigh *dn; - n = n->next; -try_again: - if (n) - goto out; - if (++state->bucket > NEIGH_HASHMASK) - goto out; - n = dn_neigh_table.hash_buckets[state->bucket]; - goto try_again; -out: - return n; -} + if (neigh->dev != s->dev) + return; -static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct neighbour *n = neigh_get_first(seq); + dn = (struct dn_neigh *) neigh; + if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) + return; - if (n) - while(*pos && (n = neigh_get_next(seq, n))) - --*pos; - return *pos ? NULL : n; -} + dn_db = (struct dn_dev *) s->dev->dn_ptr; + if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2)) + return; -static void *dn_neigh_get_idx(struct seq_file *seq, loff_t pos) -{ - void *rc; - read_lock_bh(&dn_neigh_table.lock); - rc = neigh_get_idx(seq, &pos); - if (!rc) { - read_unlock_bh(&dn_neigh_table.lock); - } - return rc; -} - -static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos) -{ - return *pos ? dn_neigh_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; + if (s->t == s->n) + s->rs = dn_find_slot(s->ptr, s->n, dn->priority); + else + s->t++; + if (s->rs == NULL) + return; + + dn_dn2eth(s->rs, dn->addr); + s->rs += 6; + *(s->rs) = neigh->nud_state & NUD_CONNECTED ? 0x80 : 0x0; + *(s->rs) |= dn->priority; + s->rs++; } -static void *dn_neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos) +int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) { - void *rc; + struct elist_cb_state state; + state.dev = dev; + state.t = 0; + state.n = n; + state.ptr = ptr; + state.rs = ptr; - if (v == SEQ_START_TOKEN) { - rc = dn_neigh_get_idx(seq, 0); - goto out; - } + neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state); - rc = neigh_get_next(seq, v); - if (rc) - goto out; - read_unlock_bh(&dn_neigh_table.lock); -out: - ++*pos; - return rc; + return state.t; } -static void dn_neigh_seq_stop(struct seq_file *seq, void *v) -{ - if (v && v != SEQ_START_TOKEN) - read_unlock_bh(&dn_neigh_table.lock); -} + +#ifdef CONFIG_PROC_FS static inline void dn_neigh_format_entry(struct seq_file *seq, struct neighbour *n) { - struct dn_neigh *dn = (struct dn_neigh *)n; + struct dn_neigh *dn = (struct dn_neigh *) n; char buf[DN_ASCBUF_LEN]; read_lock(&n->lock); @@ -662,10 +574,16 @@ static int dn_neigh_seq_show(struct seq_file *seq, void *v) return 0; } +static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos) +{ + return neigh_seq_start(seq, pos, &dn_neigh_table, + NEIGH_SEQ_NEIGH_ONLY); +} + static struct seq_operations dn_neigh_seq_ops = { .start = dn_neigh_seq_start, - .next = dn_neigh_seq_next, - .stop = dn_neigh_seq_stop, + .next = neigh_seq_next, + .stop = neigh_seq_stop, .show = dn_neigh_seq_show, }; @@ -673,11 +591,12 @@ static int dn_neigh_seq_open(struct inode *inode, struct file *file) { struct seq_file *seq; int rc = -ENOMEM; - struct dn_neigh_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + struct neigh_seq_state *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; + memset(s, 0, sizeof(*s)); rc = seq_open(file, &dn_neigh_seq_ops); if (rc) goto out_kfree;