X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fdecnet%2Fdn_neigh.c;h=66e230c3b3287072124fa52e16c2577bdde9c7a9;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=ab64b850c12b3ff9df5339808796fbb1e56fcbd5;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index ab64b850c..66e230c3b 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include #include #include +#include +#include #include #include #include @@ -92,13 +95,12 @@ static struct neigh_ops dn_phase3_ops = { struct neigh_table dn_neigh_table = { .family = PF_DECnet, .entry_size = sizeof(struct dn_neigh), - .key_len = sizeof(dn_address), + .key_len = sizeof(__le16), .hash = dn_neigh_hash, .constructor = dn_neigh_construct, .id = "dn_neigh_cache", .parms ={ .tbl = &dn_neigh_table, - .entries = 0, .base_reachable_time = 30 * HZ, .retrans_time = 1 * HZ, .gc_staletime = 60 * HZ, @@ -121,31 +123,37 @@ 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(*(__u16 *)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); if (dn_db->use_long) neigh->ops = &dn_long_ops; else neigh->ops = &dn_short_ops; + rcu_read_unlock(); if (dn->flags & DN_NDFLAG_P3) neigh->ops = &dn_phase3_ops; @@ -241,14 +249,14 @@ static int dn_long_output(struct sk_buff *skb) data = skb_push(skb, sizeof(struct dn_long_packet) + 3); lp = (struct dn_long_packet *)(data+3); - *((unsigned short *)data) = dn_htons(skb->len - 2); + *((__le16 *)data) = dn_htons(skb->len - 2); *(data + 2) = 1 | DN_RT_F_PF; /* Padding */ lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS)); lp->d_area = lp->d_subarea = 0; - dn_dn2eth(lp->d_id, dn_ntohs(cb->dst)); + dn_dn2eth(lp->d_id, cb->dst); lp->s_area = lp->s_subarea = 0; - dn_dn2eth(lp->s_id, dn_ntohs(cb->src)); + dn_dn2eth(lp->s_id, cb->src); lp->nl2 = 0; lp->visit_ct = cb->hops & 0x3f; lp->s_class = 0; @@ -285,7 +293,7 @@ static int dn_short_output(struct sk_buff *skb) } data = skb_push(skb, sizeof(struct dn_short_packet) + 2); - *((unsigned short *)data) = dn_htons(skb->len - 2); + *((__le16 *)data) = dn_htons(skb->len - 2); sp = (struct dn_short_packet *)(data+2); sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); @@ -327,7 +335,7 @@ static int dn_phase3_output(struct sk_buff *skb) } data = skb_push(skb, sizeof(struct dn_short_packet) + 2); - *((unsigned short *)data) = dn_htons(skb->len - 2); + *((__le16 *)data) = dn_htons(skb->len - 2); sp = (struct dn_short_packet *)(data + 2); sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); @@ -346,35 +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. - */ -void dn_neigh_pointopoint_notify(struct sk_buff *skb) -{ - return; -} /* * Pointopoint link receives a hello message @@ -394,9 +373,9 @@ int dn_neigh_router_hello(struct sk_buff *skb) struct neighbour *neigh; struct dn_neigh *dn; struct dn_dev *dn_db; - dn_address src; + __le16 src; - src = dn_htons(dn_eth2dn(msg->id)); + src = dn_eth2dn(msg->id); neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); @@ -412,7 +391,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; @@ -429,11 +408,14 @@ int dn_neigh_router_hello(struct sk_buff *skb) } } - if (!dn_db->router) { - dn_db->router = neigh_clone(neigh); - } else { - if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority) - neigh_release(xchg(&dn_db->router, neigh_clone(neigh))); + /* Only use routers in our area */ + if ((dn_ntohs(src)>>10) == (dn_ntohs((decnet_address))>>10)) { + if (!dn_db->router) { + dn_db->router = neigh_clone(neigh); + } else { + if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority) + neigh_release(xchg(&dn_db->router, neigh_clone(neigh))); + } } write_unlock(&neigh->lock); neigh_release(neigh); @@ -451,9 +433,9 @@ int dn_neigh_endnode_hello(struct sk_buff *skb) struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data; struct neighbour *neigh; struct dn_neigh *dn; - dn_address src; + __le16 src; - src = dn_htons(dn_eth2dn(msg->id)); + src = dn_eth2dn(msg->id); neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1); @@ -468,7 +450,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 +483,61 @@ 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; - } + struct elist_cb_state *s = _info; + struct dn_neigh *dn; - return n; -} + if (neigh->dev != s->dev) + return; -static struct neighbour *neigh_get_next(struct seq_file *seq, - struct neighbour *n) -{ - struct dn_neigh_iter_state *state = seq->private; + dn = (struct dn_neigh *) neigh; + if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2))) + return; - 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 (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 struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) +int dn_neigh_elist(struct net_device *dev, unsigned char *ptr, int n) { - struct neighbour *n = neigh_get_first(seq); + struct elist_cb_state state; - if (n) - while(*pos && (n = neigh_get_next(seq, n))) - --*pos; - return *pos ? NULL : n; -} + state.dev = dev; + state.t = 0; + state.n = n; + state.ptr = ptr; + state.rs = ptr; -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; -} + neigh_for_each(&dn_neigh_table, neigh_elist_cb, &state); -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; + return state.t; } -static void *dn_neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - void *rc; - - if (v == SEQ_START_TOKEN) { - rc = dn_neigh_get_idx(seq, 0); - goto out; - } - - rc = neigh_get_next(seq, v); - if (rc) - goto out; - read_unlock_bh(&dn_neigh_table.lock); -out: - ++*pos; - return rc; -} - -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 +564,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 +581,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;