aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTony Zelenoff <antonz@parallels.com>2012-01-26 17:28:58 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-30 12:57:34 -0500
commit84920c1420e2b4a4150e5bb45ee5a23ea4641523 (patch)
tree5115f0d9525cc7321c34bb6260ef576e091040f1 /net
parent5e6bbedd8238edbfee03d2950369edb08773cd3c (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.c90
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
2168static 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
2192nla_put_failure:
2193 nlmsg_cancel(skb, nlh);
2194 return -EMSGSIZE;
2195}
2196
2168static void neigh_update_notify(struct neighbour *neigh) 2197static 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
2246static 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;
2281out:
2282 cb->args[3] = h;
2283 cb->args[4] = idx;
2284 return rc;
2285
2286}
2287
2217static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) 2288static 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