diff options
Diffstat (limited to 'include/net/ndisc.h')
-rw-r--r-- | include/net/ndisc.h | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 23b3a7c58783..745bf741e029 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h | |||
@@ -127,13 +127,19 @@ static int ndisc_addr_option_pad(unsigned short type) | |||
127 | } | 127 | } |
128 | } | 128 | } |
129 | 129 | ||
130 | static inline int ndisc_opt_addr_space(struct net_device *dev) | ||
131 | { | ||
132 | return NDISC_OPT_SPACE(dev->addr_len + | ||
133 | ndisc_addr_option_pad(dev->type)); | ||
134 | } | ||
135 | |||
130 | static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, | 136 | static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, |
131 | struct net_device *dev) | 137 | struct net_device *dev) |
132 | { | 138 | { |
133 | u8 *lladdr = (u8 *)(p + 1); | 139 | u8 *lladdr = (u8 *)(p + 1); |
134 | int lladdrlen = p->nd_opt_len << 3; | 140 | int lladdrlen = p->nd_opt_len << 3; |
135 | int prepad = ndisc_addr_option_pad(dev->type); | 141 | int prepad = ndisc_addr_option_pad(dev->type); |
136 | if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len + prepad)) | 142 | if (lladdrlen != ndisc_opt_addr_space(dev)) |
137 | return NULL; | 143 | return NULL; |
138 | return lladdr + prepad; | 144 | return lladdr + prepad; |
139 | } | 145 | } |
@@ -148,15 +154,14 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _ | |||
148 | (p32[3] * hash_rnd[3])); | 154 | (p32[3] * hash_rnd[3])); |
149 | } | 155 | } |
150 | 156 | ||
151 | static inline struct neighbour *__ipv6_neigh_lookup(struct neigh_table *tbl, struct net_device *dev, const void *pkey) | 157 | static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey) |
152 | { | 158 | { |
153 | struct neigh_hash_table *nht; | 159 | struct neigh_hash_table *nht; |
154 | const u32 *p32 = pkey; | 160 | const u32 *p32 = pkey; |
155 | struct neighbour *n; | 161 | struct neighbour *n; |
156 | u32 hash_val; | 162 | u32 hash_val; |
157 | 163 | ||
158 | rcu_read_lock_bh(); | 164 | nht = rcu_dereference_bh(nd_tbl.nht); |
159 | nht = rcu_dereference_bh(tbl->nht); | ||
160 | hash_val = ndisc_hashfn(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); | 165 | hash_val = ndisc_hashfn(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); |
161 | for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); | 166 | for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); |
162 | n != NULL; | 167 | n != NULL; |
@@ -164,12 +169,21 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct neigh_table *tbl, str | |||
164 | u32 *n32 = (u32 *) n->primary_key; | 169 | u32 *n32 = (u32 *) n->primary_key; |
165 | if (n->dev == dev && | 170 | if (n->dev == dev && |
166 | ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) | | 171 | ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) | |
167 | (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0) { | 172 | (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0) |
168 | if (!atomic_inc_not_zero(&n->refcnt)) | 173 | return n; |
169 | n = NULL; | ||
170 | break; | ||
171 | } | ||
172 | } | 174 | } |
175 | |||
176 | return NULL; | ||
177 | } | ||
178 | |||
179 | static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey) | ||
180 | { | ||
181 | struct neighbour *n; | ||
182 | |||
183 | rcu_read_lock_bh(); | ||
184 | n = __ipv6_neigh_lookup_noref(dev, pkey); | ||
185 | if (n && !atomic_inc_not_zero(&n->refcnt)) | ||
186 | n = NULL; | ||
173 | rcu_read_unlock_bh(); | 187 | rcu_read_unlock_bh(); |
174 | 188 | ||
175 | return n; | 189 | return n; |