-struct arp_iter_state {
- int is_pneigh, bucket;
-};
-
-static struct neighbour *neigh_get_first(struct seq_file *seq)
-{
- struct arp_iter_state* state = seq->private;
- struct neighbour *n = NULL;
-
- state->is_pneigh = 0;
-
- for (state->bucket = 0;
- state->bucket <= NEIGH_HASHMASK;
- ++state->bucket) {
- n = arp_tbl.hash_buckets[state->bucket];
- while (n && !(n->nud_state & ~NUD_NOARP))
- n = n->next;
- if (n)
- break;
- }
-
- return n;
-}
-
-static struct neighbour *neigh_get_next(struct seq_file *seq,
- struct neighbour *n)
-{
- struct arp_iter_state* state = seq->private;
-
- do {
- n = n->next;
- /* Don't confuse "arp -a" w/ magic entries */
-try_again:
- ;
- } while (n && !(n->nud_state & ~NUD_NOARP));
-
- if (n)
- goto out;
- if (++state->bucket > NEIGH_HASHMASK)
- goto out;
- n = arp_tbl.hash_buckets[state->bucket];
- goto try_again;
-out:
- return n;
-}
-
-static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
-{
- struct neighbour *n = neigh_get_first(seq);
-
- if (n)
- while (*pos && (n = neigh_get_next(seq, n)))
- --*pos;
- return *pos ? NULL : n;
-}
-
-static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
-{
- struct arp_iter_state* state = seq->private;
- struct pneigh_entry *pn;
-
- state->is_pneigh = 1;
-
- for (state->bucket = 0;
- state->bucket <= PNEIGH_HASHMASK;
- ++state->bucket) {
- pn = arp_tbl.phash_buckets[state->bucket];
- if (pn)
- break;
- }
- return pn;
-}
-
-static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
- struct pneigh_entry *pn)
-{
- struct arp_iter_state* state = seq->private;
-
- pn = pn->next;
- while (!pn) {
- if (++state->bucket > PNEIGH_HASHMASK)
- break;
- pn = arp_tbl.phash_buckets[state->bucket];
- }
- return pn;
-}
-
-static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t pos)
-{
- struct pneigh_entry *pn = pneigh_get_first(seq);
-
- if (pn)
- while (pos && (pn = pneigh_get_next(seq, pn)))
- --pos;
- return pos ? NULL : pn;
-}
-
-static void *arp_get_idx(struct seq_file *seq, loff_t pos)
-{
- void *rc;
-
- read_lock_bh(&arp_tbl.lock);
- rc = neigh_get_idx(seq, &pos);
-
- if (!rc) {
- read_unlock_bh(&arp_tbl.lock);
- rc = pneigh_get_idx(seq, pos);
- }
- return rc;
-}
-
-static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
-{
- struct arp_iter_state* state = seq->private;
-
- state->is_pneigh = 0;
- state->bucket = 0;
- return *pos ? arp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
-}
-
-static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
- void *rc;
- struct arp_iter_state* state;
-
- if (v == SEQ_START_TOKEN) {
- rc = arp_get_idx(seq, 0);
- goto out;
- }
-
- state = seq->private;
- if (!state->is_pneigh) {
- rc = neigh_get_next(seq, v);
- if (rc)
- goto out;
- read_unlock_bh(&arp_tbl.lock);
- rc = pneigh_get_first(seq);
- } else
- rc = pneigh_get_next(seq, v);
-out:
- ++*pos;
- return rc;
-}
-
-static void arp_seq_stop(struct seq_file *seq, void *v)
-{
- struct arp_iter_state* state = seq->private;
-
- if (!state->is_pneigh && v != SEQ_START_TOKEN)
- read_unlock_bh(&arp_tbl.lock);
-}
-