diff options
author | Tony Zelenoff <antonz@parallels.com> | 2012-01-26 17:28:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-01-30 12:57:34 -0500 |
commit | 84920c1420e2b4a4150e5bb45ee5a23ea4641523 (patch) | |
tree | 5115f0d9525cc7321c34bb6260ef576e091040f1 /net | |
parent | 5e6bbedd8238edbfee03d2950369edb08773cd3c (diff) |
net: Allow ipv6 proxies and arp proxies be shown with iproute2
Add ability to return neighbour proxies list to caller if
it sent full ndmsg structure and has NTF_PROXY flag set.
Before this patch (and before iproute2 patches):
$ ip neigh add proxy 2001::1 dev eth0
$ ip -6 neigh show
$
After it and with applied iproute2 patches:
$ ip neigh add proxy 2001::1 dev eth0
$ ip -6 neigh show
2001::1 dev eth0 proxy
$
Compatibility with old versions of iproute2 is not broken,
kernel checks for incoming structure size and properly
works if old structure is came.
[v2]
* changed comments style.
* removed useless line with continue and curly bracket.
* changed incoming message size check from equal to more or
equal.
CC: davem@davemloft.net
CC: kuznet@ms2.inr.ac.ru
CC: netdev@vger.kernel.org
CC: xemul@parallels.com
Signed-off-by: Tony Zelenoff <antonz@parallels.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/neighbour.c | 90 |
1 files changed, 87 insertions, 3 deletions
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e287346e0934..f98ec444133a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -2165,6 +2165,35 @@ nla_put_failure: | |||
2165 | return -EMSGSIZE; | 2165 | return -EMSGSIZE; |
2166 | } | 2166 | } |
2167 | 2167 | ||
2168 | static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn, | ||
2169 | u32 pid, u32 seq, int type, unsigned int flags, | ||
2170 | struct neigh_table *tbl) | ||
2171 | { | ||
2172 | struct nlmsghdr *nlh; | ||
2173 | struct ndmsg *ndm; | ||
2174 | |||
2175 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); | ||
2176 | if (nlh == NULL) | ||
2177 | return -EMSGSIZE; | ||
2178 | |||
2179 | ndm = nlmsg_data(nlh); | ||
2180 | ndm->ndm_family = tbl->family; | ||
2181 | ndm->ndm_pad1 = 0; | ||
2182 | ndm->ndm_pad2 = 0; | ||
2183 | ndm->ndm_flags = pn->flags | NTF_PROXY; | ||
2184 | ndm->ndm_type = NDA_DST; | ||
2185 | ndm->ndm_ifindex = pn->dev->ifindex; | ||
2186 | ndm->ndm_state = NUD_NONE; | ||
2187 | |||
2188 | NLA_PUT(skb, NDA_DST, tbl->key_len, pn->key); | ||
2189 | |||
2190 | return nlmsg_end(skb, nlh); | ||
2191 | |||
2192 | nla_put_failure: | ||
2193 | nlmsg_cancel(skb, nlh); | ||
2194 | return -EMSGSIZE; | ||
2195 | } | ||
2196 | |||
2168 | static void neigh_update_notify(struct neighbour *neigh) | 2197 | static void neigh_update_notify(struct neighbour *neigh) |
2169 | { | 2198 | { |
2170 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); | 2199 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); |
@@ -2214,23 +2243,78 @@ out: | |||
2214 | return rc; | 2243 | return rc; |
2215 | } | 2244 | } |
2216 | 2245 | ||
2246 | static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, | ||
2247 | struct netlink_callback *cb) | ||
2248 | { | ||
2249 | struct pneigh_entry *n; | ||
2250 | struct net *net = sock_net(skb->sk); | ||
2251 | int rc, h, s_h = cb->args[3]; | ||
2252 | int idx, s_idx = idx = cb->args[4]; | ||
2253 | |||
2254 | read_lock_bh(&tbl->lock); | ||
2255 | |||
2256 | for (h = 0; h <= PNEIGH_HASHMASK; h++) { | ||
2257 | if (h < s_h) | ||
2258 | continue; | ||
2259 | if (h > s_h) | ||
2260 | s_idx = 0; | ||
2261 | for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { | ||
2262 | if (dev_net(n->dev) != net) | ||
2263 | continue; | ||
2264 | if (idx < s_idx) | ||
2265 | goto next; | ||
2266 | if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid, | ||
2267 | cb->nlh->nlmsg_seq, | ||
2268 | RTM_NEWNEIGH, | ||
2269 | NLM_F_MULTI, tbl) <= 0) { | ||
2270 | read_unlock_bh(&tbl->lock); | ||
2271 | rc = -1; | ||
2272 | goto out; | ||
2273 | } | ||
2274 | next: | ||
2275 | idx++; | ||
2276 | } | ||
2277 | } | ||
2278 | |||
2279 | read_unlock_bh(&tbl->lock); | ||
2280 | rc = skb->len; | ||
2281 | out: | ||
2282 | cb->args[3] = h; | ||
2283 | cb->args[4] = idx; | ||
2284 | return rc; | ||
2285 | |||
2286 | } | ||
2287 | |||
2217 | static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) | 2288 | static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) |
2218 | { | 2289 | { |
2219 | struct neigh_table *tbl; | 2290 | struct neigh_table *tbl; |
2220 | int t, family, s_t; | 2291 | int t, family, s_t; |
2292 | int proxy = 0; | ||
2293 | int err = 0; | ||
2221 | 2294 | ||
2222 | read_lock(&neigh_tbl_lock); | 2295 | read_lock(&neigh_tbl_lock); |
2223 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; | 2296 | family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; |
2297 | |||
2298 | /* check for full ndmsg structure presence, family member is | ||
2299 | * the same for both structures | ||
2300 | */ | ||
2301 | if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) && | ||
2302 | ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY) | ||
2303 | proxy = 1; | ||
2304 | |||
2224 | s_t = cb->args[0]; | 2305 | s_t = cb->args[0]; |
2225 | 2306 | ||
2226 | for (tbl = neigh_tables, t = 0; tbl; tbl = tbl->next, t++) { | 2307 | for (tbl = neigh_tables, t = 0; tbl && (err >= 0); |
2308 | tbl = tbl->next, t++) { | ||
2227 | if (t < s_t || (family && tbl->family != family)) | 2309 | if (t < s_t || (family && tbl->family != family)) |
2228 | continue; | 2310 | continue; |
2229 | if (t > s_t) | 2311 | if (t > s_t) |
2230 | memset(&cb->args[1], 0, sizeof(cb->args) - | 2312 | memset(&cb->args[1], 0, sizeof(cb->args) - |
2231 | sizeof(cb->args[0])); | 2313 | sizeof(cb->args[0])); |
2232 | if (neigh_dump_table(tbl, skb, cb) < 0) | 2314 | if (proxy) |
2233 | break; | 2315 | err = pneigh_dump_table(tbl, skb, cb); |
2316 | else | ||
2317 | err = neigh_dump_table(tbl, skb, cb); | ||
2234 | } | 2318 | } |
2235 | read_unlock(&neigh_tbl_lock); | 2319 | read_unlock(&neigh_tbl_lock); |
2236 | 2320 | ||