Blame view
net/ipv6/ip6mr.c
58.9 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
7bc570c8b [IPV6] MROUTE: Su... |
2 3 4 5 6 7 8 9 10 11 |
/* * Linux IPv6 multicast routing support for BSD pim6sd * Based on net/ipv4/ipmr.c. * * (c) 2004 Mickael Hoerdt, <hoerdt@clarinet.u-strasbg.fr> * LSIIT Laboratory, Strasbourg, France * (c) 2004 Jean-Philippe Andriot, <jean-philippe.andriot@6WIND.com> * 6WIND, Paris, France * Copyright (C)2007,2008 USAGI/WIDE Project * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
7bc570c8b [IPV6] MROUTE: Su... |
12 |
*/ |
7c0f6ba68 Replace <asm/uacc... |
13 |
#include <linux/uaccess.h> |
7bc570c8b [IPV6] MROUTE: Su... |
14 15 16 |
#include <linux/types.h> #include <linux/sched.h> #include <linux/errno.h> |
7bc570c8b [IPV6] MROUTE: Su... |
17 18 19 20 21 |
#include <linux/mm.h> #include <linux/kernel.h> #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/socket.h> |
7bc570c8b [IPV6] MROUTE: Su... |
22 23 24 |
#include <linux/inet.h> #include <linux/netdevice.h> #include <linux/inetdevice.h> |
7bc570c8b [IPV6] MROUTE: Su... |
25 26 |
#include <linux/proc_fs.h> #include <linux/seq_file.h> |
7bc570c8b [IPV6] MROUTE: Su... |
27 |
#include <linux/init.h> |
e2d57766e net: Provide comp... |
28 |
#include <linux/compat.h> |
0eb71a9da rhashtable: split... |
29 |
#include <linux/rhashtable.h> |
7bc570c8b [IPV6] MROUTE: Su... |
30 31 |
#include <net/protocol.h> #include <linux/skbuff.h> |
7bc570c8b [IPV6] MROUTE: Su... |
32 |
#include <net/raw.h> |
7bc570c8b [IPV6] MROUTE: Su... |
33 34 |
#include <linux/notifier.h> #include <linux/if_arp.h> |
7bc570c8b [IPV6] MROUTE: Su... |
35 36 |
#include <net/checksum.h> #include <net/netlink.h> |
d1db275dd ipv6: ip6mr: supp... |
37 |
#include <net/fib_rules.h> |
7bc570c8b [IPV6] MROUTE: Su... |
38 39 40 41 |
#include <net/ipv6.h> #include <net/ip6_route.h> #include <linux/mroute6.h> |
14fb64e1f [IPV6] MROUTE: Su... |
42 |
#include <linux/pim.h> |
7bc570c8b [IPV6] MROUTE: Su... |
43 44 |
#include <net/addrconf.h> #include <linux/netfilter_ipv6.h> |
bc3b2d7fb net: Add export.h... |
45 |
#include <linux/export.h> |
5d6e430d3 ipv6: compile fix... |
46 |
#include <net/ip6_checksum.h> |
d67b8c616 netconf: advertis... |
47 |
#include <linux/netconf.h> |
cb9f1b783 ip: validate head... |
48 |
#include <net/ip_tunnels.h> |
7bc570c8b [IPV6] MROUTE: Su... |
49 |
|
69d2c8676 ip6mr: Fix potent... |
50 |
#include <linux/nospec.h> |
d1db275dd ipv6: ip6mr: supp... |
51 52 53 54 55 |
struct ip6mr_rule { struct fib_rule common; }; struct ip6mr_result { |
b70432f73 mroute*: Make mr_... |
56 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
57 |
}; |
7bc570c8b [IPV6] MROUTE: Su... |
58 59 60 61 62 |
/* Big lock, protecting vif table, mrt cache and mroute socket state. Note that the changes are semaphored via rtnl_lock. */ static DEFINE_RWLOCK(mrt_lock); |
b70432f73 mroute*: Make mr_... |
63 |
/* Multicast router control variables */ |
7bc570c8b [IPV6] MROUTE: Su... |
64 |
|
7bc570c8b [IPV6] MROUTE: Su... |
65 66 67 68 69 70 71 72 73 74 75 76 |
/* Special spinlock for queue of unresolved entries */ static DEFINE_SPINLOCK(mfc_unres_lock); /* We return to original Alan's scheme. Hash table of resolved entries is changed only in process context and protected with weak lock mrt_lock. Queue of unresolved entries is protected with strong spinlock mfc_unres_lock. In this case data path is free of exclusive locks at all. */ static struct kmem_cache *mrt_cachep __read_mostly; |
b70432f73 mroute*: Make mr_... |
77 78 |
static struct mr_table *ip6mr_new_table(struct net *net, u32 id); static void ip6mr_free_table(struct mr_table *mrt); |
d1db275dd ipv6: ip6mr: supp... |
79 |
|
b70432f73 mroute*: Make mr_... |
80 |
static void ip6_mr_forward(struct net *net, struct mr_table *mrt, |
e4a38c0c4 ipv6: add vrf tab... |
81 82 |
struct net_device *dev, struct sk_buff *skb, struct mfc6_cache *cache); |
b70432f73 mroute*: Make mr_... |
83 |
static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, |
8229efdae netns: ip6mr: ena... |
84 |
mifi_t mifi, int assert); |
b70432f73 mroute*: Make mr_... |
85 |
static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc, |
812e44dd1 ip6mr: advertise ... |
86 |
int cmd); |
b70432f73 mroute*: Make mr_... |
87 |
static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); |
5b285cac3 ipv6: ip6mr: add ... |
88 89 |
static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb); |
ca8d4794f ipmr: ip6mr: Crea... |
90 |
static void mroute_clean_tables(struct mr_table *mrt, int flags); |
e99e88a9d treewide: setup_t... |
91 |
static void ipmr_expire_process(struct timer_list *t); |
d1db275dd ipv6: ip6mr: supp... |
92 93 |
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES |
8ffb335e8 ip6mr: fix a typo... |
94 |
#define ip6mr_for_each_table(mrt, net) \ |
28b380e28 ip6mr: Fix RCU li... |
95 |
list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list, \ |
b6dd5acde ipv6: Fix suspici... |
96 97 |
lockdep_rtnl_is_held() || \ list_empty(&net->ipv6.mr6_tables)) |
d1db275dd ipv6: ip6mr: supp... |
98 |
|
7b0db8573 ipmr, ip6mr: Unit... |
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
static struct mr_table *ip6mr_mr_table_iter(struct net *net, struct mr_table *mrt) { struct mr_table *ret; if (!mrt) ret = list_entry_rcu(net->ipv6.mr6_tables.next, struct mr_table, list); else ret = list_entry_rcu(mrt->list.next, struct mr_table, list); if (&ret->list == &net->ipv6.mr6_tables) return NULL; return ret; } |
b70432f73 mroute*: Make mr_... |
115 |
static struct mr_table *ip6mr_get_table(struct net *net, u32 id) |
d1db275dd ipv6: ip6mr: supp... |
116 |
{ |
b70432f73 mroute*: Make mr_... |
117 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
118 119 120 121 122 123 124 |
ip6mr_for_each_table(mrt, net) { if (mrt->id == id) return mrt; } return NULL; } |
4c9483b2f ipv6: Convert to ... |
125 |
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, |
b70432f73 mroute*: Make mr_... |
126 |
struct mr_table **mrt) |
d1db275dd ipv6: ip6mr: supp... |
127 |
{ |
d1db275dd ipv6: ip6mr: supp... |
128 |
int err; |
95f4a45de net: avoid refere... |
129 130 131 132 133 |
struct ip6mr_result res; struct fib_lookup_arg arg = { .result = &res, .flags = FIB_LOOKUP_NOREF, }; |
d1db275dd ipv6: ip6mr: supp... |
134 |
|
e4a38c0c4 ipv6: add vrf tab... |
135 136 |
/* update flow if oif or iif point to device enslaved to l3mdev */ l3mdev_update_flow(net, flowi6_to_flowi(flp6)); |
4c9483b2f ipv6: Convert to ... |
137 138 |
err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flowi6_to_flowi(flp6), 0, &arg); |
d1db275dd ipv6: ip6mr: supp... |
139 140 141 142 143 144 145 146 147 148 |
if (err < 0) return err; *mrt = res.mrt; return 0; } static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp, int flags, struct fib_lookup_arg *arg) { struct ip6mr_result *res = arg->result; |
b70432f73 mroute*: Make mr_... |
149 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
150 151 152 153 154 155 156 157 158 159 160 161 |
switch (rule->action) { case FR_ACT_TO_TBL: break; case FR_ACT_UNREACHABLE: return -ENETUNREACH; case FR_ACT_PROHIBIT: return -EACCES; case FR_ACT_BLACKHOLE: default: return -EINVAL; } |
e4a38c0c4 ipv6: add vrf tab... |
162 163 164 |
arg->table = fib_rule_get_table(rule, arg); mrt = ip6mr_get_table(rule->fr_net, arg->table); |
63159f29b ipv6: coding styl... |
165 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
return -EAGAIN; res->mrt = mrt; return 0; } static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags) { return 1; } static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = { FRA_GENERIC_POLICY, }; static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb, |
b16fb418b net: fib_rules: a... |
181 182 |
struct fib_rule_hdr *frh, struct nlattr **tb, struct netlink_ext_ack *extack) |
d1db275dd ipv6: ip6mr: supp... |
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
{ return 0; } static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, struct nlattr **tb) { return 1; } static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb, struct fib_rule_hdr *frh) { frh->dst_len = 0; frh->src_len = 0; frh->tos = 0; return 0; } |
04a6f82cf sections: fix sec... |
201 |
static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = { |
d1db275dd ipv6: ip6mr: supp... |
202 203 204 205 206 207 208 |
.family = RTNL_FAMILY_IP6MR, .rule_size = sizeof(struct ip6mr_rule), .addr_size = sizeof(struct in6_addr), .action = ip6mr_rule_action, .match = ip6mr_rule_match, .configure = ip6mr_rule_configure, .compare = ip6mr_rule_compare, |
d1db275dd ipv6: ip6mr: supp... |
209 210 211 212 213 214 215 216 217 |
.fill = ip6mr_rule_fill, .nlgroup = RTNLGRP_IPV6_RULE, .policy = ip6mr_rule_policy, .owner = THIS_MODULE, }; static int __net_init ip6mr_rules_init(struct net *net) { struct fib_rules_ops *ops; |
b70432f73 mroute*: Make mr_... |
218 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
219 220 221 222 223 224 225 226 227 |
int err; ops = fib_rules_register(&ip6mr_rules_ops_template, net); if (IS_ERR(ops)) return PTR_ERR(ops); INIT_LIST_HEAD(&net->ipv6.mr6_tables); mrt = ip6mr_new_table(net, RT6_TABLE_DFLT); |
e783bb00a ipmr: fix error p... |
228 229 |
if (IS_ERR(mrt)) { err = PTR_ERR(mrt); |
d1db275dd ipv6: ip6mr: supp... |
230 231 232 233 234 235 236 237 238 239 240 |
goto err1; } err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0); if (err < 0) goto err2; net->ipv6.mr6_rules_ops = ops; return 0; err2: |
f243e5a78 ipmr,ip6mr: call ... |
241 |
ip6mr_free_table(mrt); |
d1db275dd ipv6: ip6mr: supp... |
242 243 244 245 246 247 248 |
err1: fib_rules_unregister(ops); return err; } static void __net_exit ip6mr_rules_exit(struct net *net) { |
b70432f73 mroute*: Make mr_... |
249 |
struct mr_table *mrt, *next; |
d1db275dd ipv6: ip6mr: supp... |
250 |
|
905a6f96a ipv6: take rtnl_l... |
251 |
rtnl_lock(); |
035320d54 ipmr: dont corrup... |
252 253 |
list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { list_del(&mrt->list); |
d1db275dd ipv6: ip6mr: supp... |
254 |
ip6mr_free_table(mrt); |
035320d54 ipmr: dont corrup... |
255 |
} |
d1db275dd ipv6: ip6mr: supp... |
256 |
fib_rules_unregister(net->ipv6.mr6_rules_ops); |
419df12fb net: move fib_rul... |
257 |
rtnl_unlock(); |
d1db275dd ipv6: ip6mr: supp... |
258 |
} |
088aa3eec ip6mr: Support fi... |
259 |
|
b7a595577 net: fib_notifier... |
260 261 |
static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb, struct netlink_ext_ack *extack) |
088aa3eec ip6mr: Support fi... |
262 |
{ |
b7a595577 net: fib_notifier... |
263 |
return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR, extack); |
088aa3eec ip6mr: Support fi... |
264 265 266 267 268 269 |
} static unsigned int ip6mr_rules_seq_read(struct net *net) { return fib_rules_seq_read(net, RTNL_FAMILY_IP6MR); } |
d3c07e5b9 ip6mr: Add API fo... |
270 271 272 273 274 275 276 |
bool ip6mr_rule_default(const struct fib_rule *rule) { return fib_rule_matchall(rule) && rule->action == FR_ACT_TO_TBL && rule->table == RT6_TABLE_DFLT && !rule->l3mdev; } EXPORT_SYMBOL(ip6mr_rule_default); |
d1db275dd ipv6: ip6mr: supp... |
277 278 279 |
#else #define ip6mr_for_each_table(mrt, net) \ for (mrt = net->ipv6.mrt6; mrt; mrt = NULL) |
7b0db8573 ipmr, ip6mr: Unit... |
280 281 282 283 284 285 286 |
static struct mr_table *ip6mr_mr_table_iter(struct net *net, struct mr_table *mrt) { if (!mrt) return net->ipv6.mrt6; return NULL; } |
b70432f73 mroute*: Make mr_... |
287 |
static struct mr_table *ip6mr_get_table(struct net *net, u32 id) |
d1db275dd ipv6: ip6mr: supp... |
288 289 290 |
{ return net->ipv6.mrt6; } |
4c9483b2f ipv6: Convert to ... |
291 |
static int ip6mr_fib_lookup(struct net *net, struct flowi6 *flp6, |
b70432f73 mroute*: Make mr_... |
292 |
struct mr_table **mrt) |
d1db275dd ipv6: ip6mr: supp... |
293 294 295 296 297 298 299 |
{ *mrt = net->ipv6.mrt6; return 0; } static int __net_init ip6mr_rules_init(struct net *net) { |
e783bb00a ipmr: fix error p... |
300 301 302 303 304 305 306 |
struct mr_table *mrt; mrt = ip6mr_new_table(net, RT6_TABLE_DFLT); if (IS_ERR(mrt)) return PTR_ERR(mrt); net->ipv6.mrt6 = mrt; return 0; |
d1db275dd ipv6: ip6mr: supp... |
307 308 309 310 |
} static void __net_exit ip6mr_rules_exit(struct net *net) { |
905a6f96a ipv6: take rtnl_l... |
311 |
rtnl_lock(); |
d1db275dd ipv6: ip6mr: supp... |
312 |
ip6mr_free_table(net->ipv6.mrt6); |
905a6f96a ipv6: take rtnl_l... |
313 314 |
net->ipv6.mrt6 = NULL; rtnl_unlock(); |
d1db275dd ipv6: ip6mr: supp... |
315 |
} |
088aa3eec ip6mr: Support fi... |
316 |
|
b7a595577 net: fib_notifier... |
317 318 |
static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb, struct netlink_ext_ack *extack) |
088aa3eec ip6mr: Support fi... |
319 320 321 322 323 324 325 326 |
{ return 0; } static unsigned int ip6mr_rules_seq_read(struct net *net) { return 0; } |
d1db275dd ipv6: ip6mr: supp... |
327 |
#endif |
87c418bf1 ip6mr: Align hash... |
328 329 330 331 332 333 334 335 336 337 338 |
static int ip6mr_hash_cmp(struct rhashtable_compare_arg *arg, const void *ptr) { const struct mfc6_cache_cmp_arg *cmparg = arg->key; struct mfc6_cache *c = (struct mfc6_cache *)ptr; return !ipv6_addr_equal(&c->mf6c_mcastgrp, &cmparg->mf6c_mcastgrp) || !ipv6_addr_equal(&c->mf6c_origin, &cmparg->mf6c_origin); } static const struct rhashtable_params ip6mr_rht_params = { |
494fff563 ipmr, ip6mr: Make... |
339 |
.head_offset = offsetof(struct mr_mfc, mnode), |
87c418bf1 ip6mr: Align hash... |
340 341 342 |
.key_offset = offsetof(struct mfc6_cache, cmparg), .key_len = sizeof(struct mfc6_cache_cmp_arg), .nelem_hint = 3, |
87c418bf1 ip6mr: Align hash... |
343 344 345 |
.obj_cmpfn = ip6mr_hash_cmp, .automatic_shrinking = true, }; |
0bbbf0e7d ipmr, ip6mr: Unit... |
346 347 348 349 350 351 352 |
static void ip6mr_new_table_set(struct mr_table *mrt, struct net *net) { #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables); #endif } |
845c9a7ae ipmr, ip6mr: Unit... |
353 354 355 356 357 358 359 360 361 |
static struct mfc6_cache_cmp_arg ip6mr_mr_table_ops_cmparg_any = { .mf6c_origin = IN6ADDR_ANY_INIT, .mf6c_mcastgrp = IN6ADDR_ANY_INIT, }; static struct mr_table_ops ip6mr_mr_table_ops = { .rht_params = &ip6mr_rht_params, .cmparg_any = &ip6mr_mr_table_ops_cmparg_any, }; |
b70432f73 mroute*: Make mr_... |
362 |
static struct mr_table *ip6mr_new_table(struct net *net, u32 id) |
d1db275dd ipv6: ip6mr: supp... |
363 |
{ |
b70432f73 mroute*: Make mr_... |
364 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
365 366 |
mrt = ip6mr_get_table(net, id); |
53b24b8f9 ipv6: coding styl... |
367 |
if (mrt) |
d1db275dd ipv6: ip6mr: supp... |
368 |
return mrt; |
845c9a7ae ipmr, ip6mr: Unit... |
369 |
return mr_table_alloc(net, id, &ip6mr_mr_table_ops, |
0bbbf0e7d ipmr, ip6mr: Unit... |
370 |
ipmr_expire_process, ip6mr_new_table_set); |
d1db275dd ipv6: ip6mr: supp... |
371 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
372 |
|
b70432f73 mroute*: Make mr_... |
373 |
static void ip6mr_free_table(struct mr_table *mrt) |
d1db275dd ipv6: ip6mr: supp... |
374 |
{ |
7ba0c47c3 ip6mr: call del_t... |
375 |
del_timer_sync(&mrt->ipmr_expire_timer); |
ca8d4794f ipmr: ip6mr: Crea... |
376 377 |
mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC | MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC); |
b70432f73 mroute*: Make mr_... |
378 |
rhltable_destroy(&mrt->mfc_hash); |
d1db275dd ipv6: ip6mr: supp... |
379 380 |
kfree(mrt); } |
7bc570c8b [IPV6] MROUTE: Su... |
381 382 |
#ifdef CONFIG_PROC_FS |
c8d619680 ipmr, ip6mr: Unit... |
383 384 |
/* The /proc interfaces to multicast routing * /proc/ip6_mr_cache /proc/ip6_mr_vif |
7bc570c8b [IPV6] MROUTE: Su... |
385 |
*/ |
7bc570c8b [IPV6] MROUTE: Su... |
386 387 388 |
static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) __acquires(mrt_lock) { |
3feda6b46 ipmr, ip6mr: Unit... |
389 |
struct mr_vif_iter *iter = seq->private; |
8b90fc7e5 netns: ip6mr: dec... |
390 |
struct net *net = seq_file_net(seq); |
b70432f73 mroute*: Make mr_... |
391 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
392 393 |
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
394 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
395 396 397 |
return ERR_PTR(-ENOENT); iter->mrt = mrt; |
8b90fc7e5 netns: ip6mr: dec... |
398 |
|
7bc570c8b [IPV6] MROUTE: Su... |
399 |
read_lock(&mrt_lock); |
3feda6b46 ipmr, ip6mr: Unit... |
400 |
return mr_vif_seq_start(seq, pos); |
7bc570c8b [IPV6] MROUTE: Su... |
401 402 403 404 405 406 407 408 409 410 |
} static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v) __releases(mrt_lock) { read_unlock(&mrt_lock); } static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) { |
3feda6b46 ipmr, ip6mr: Unit... |
411 |
struct mr_vif_iter *iter = seq->private; |
b70432f73 mroute*: Make mr_... |
412 |
struct mr_table *mrt = iter->mrt; |
8b90fc7e5 netns: ip6mr: dec... |
413 |
|
7bc570c8b [IPV6] MROUTE: Su... |
414 415 416 417 418 |
if (v == SEQ_START_TOKEN) { seq_puts(seq, "Interface BytesIn PktsIn BytesOut PktsOut Flags "); } else { |
6853f21f7 ipmr,ipmr6: Defin... |
419 |
const struct vif_device *vif = v; |
7bc570c8b [IPV6] MROUTE: Su... |
420 421 422 |
const char *name = vif->dev ? vif->dev->name : "none"; seq_printf(seq, |
d430a227d bogus format in i... |
423 424 |
"%2td %-10s %8ld %7ld %8ld %7ld %05X ", |
b70432f73 mroute*: Make mr_... |
425 |
vif - mrt->vif_table, |
7bc570c8b [IPV6] MROUTE: Su... |
426 427 428 429 430 431 |
name, vif->bytes_in, vif->pkt_in, vif->bytes_out, vif->pkt_out, vif->flags); } return 0; } |
98147d527 net: seq_operatio... |
432 |
static const struct seq_operations ip6mr_vif_seq_ops = { |
7bc570c8b [IPV6] MROUTE: Su... |
433 |
.start = ip6mr_vif_seq_start, |
3feda6b46 ipmr, ip6mr: Unit... |
434 |
.next = mr_vif_seq_next, |
7bc570c8b [IPV6] MROUTE: Su... |
435 436 437 |
.stop = ip6mr_vif_seq_stop, .show = ip6mr_vif_seq_show, }; |
7bc570c8b [IPV6] MROUTE: Su... |
438 439 |
static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) { |
8b90fc7e5 netns: ip6mr: dec... |
440 |
struct net *net = seq_file_net(seq); |
b70432f73 mroute*: Make mr_... |
441 |
struct mr_table *mrt; |
8b90fc7e5 netns: ip6mr: dec... |
442 |
|
d1db275dd ipv6: ip6mr: supp... |
443 |
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
444 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
445 |
return ERR_PTR(-ENOENT); |
c8d619680 ipmr, ip6mr: Unit... |
446 |
return mr_mfc_seq_start(seq, pos, mrt, &mfc_unres_lock); |
7bc570c8b [IPV6] MROUTE: Su... |
447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
} static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) { int n; if (v == SEQ_START_TOKEN) { seq_puts(seq, "Group " "Origin " "Iif Pkts Bytes Wrong Oifs "); } else { const struct mfc6_cache *mfc = v; |
c8d619680 ipmr, ip6mr: Unit... |
461 |
const struct mr_mfc_iter *it = seq->private; |
b70432f73 mroute*: Make mr_... |
462 |
struct mr_table *mrt = it->mrt; |
7bc570c8b [IPV6] MROUTE: Su... |
463 |
|
999890b21 net: /proc/net/ip... |
464 |
seq_printf(seq, "%pI6 %pI6 %-3hd", |
0c6ce78ab net: replace uses... |
465 |
&mfc->mf6c_mcastgrp, &mfc->mf6c_origin, |
494fff563 ipmr, ip6mr: Make... |
466 |
mfc->_c.mfc_parent); |
7bc570c8b [IPV6] MROUTE: Su... |
467 |
|
b70432f73 mroute*: Make mr_... |
468 |
if (it->cache != &mrt->mfc_unres_queue) { |
1ea472e2d net: fix /proc/ne... |
469 |
seq_printf(seq, " %8lu %8lu %8lu", |
494fff563 ipmr, ip6mr: Make... |
470 471 472 473 474 |
mfc->_c.mfc_un.res.pkt, mfc->_c.mfc_un.res.bytes, mfc->_c.mfc_un.res.wrong_if); for (n = mfc->_c.mfc_un.res.minvif; n < mfc->_c.mfc_un.res.maxvif; n++) { |
b70432f73 mroute*: Make mr_... |
475 |
if (VIF_EXISTS(mrt, n) && |
494fff563 ipmr, ip6mr: Make... |
476 |
mfc->_c.mfc_un.res.ttls[n] < 255) |
7bc570c8b [IPV6] MROUTE: Su... |
477 |
seq_printf(seq, |
494fff563 ipmr, ip6mr: Make... |
478 479 |
" %2d:%-3d", n, mfc->_c.mfc_un.res.ttls[n]); |
7bc570c8b [IPV6] MROUTE: Su... |
480 |
} |
1ea472e2d net: fix /proc/ne... |
481 482 483 484 485 |
} else { /* unresolved mfc_caches don't contain * pkt, bytes and wrong_if values */ seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul); |
7bc570c8b [IPV6] MROUTE: Su... |
486 487 488 489 490 491 |
} seq_putc(seq, ' '); } return 0; } |
88e9d34c7 seq_file: constif... |
492 |
static const struct seq_operations ipmr_mfc_seq_ops = { |
7bc570c8b [IPV6] MROUTE: Su... |
493 |
.start = ipmr_mfc_seq_start, |
c8d619680 ipmr, ip6mr: Unit... |
494 495 |
.next = mr_mfc_seq_next, .stop = mr_mfc_seq_stop, |
7bc570c8b [IPV6] MROUTE: Su... |
496 497 |
.show = ipmr_mfc_seq_show, }; |
7bc570c8b [IPV6] MROUTE: Su... |
498 |
#endif |
14fb64e1f [IPV6] MROUTE: Su... |
499 |
#ifdef CONFIG_IPV6_PIMSM_V2 |
14fb64e1f [IPV6] MROUTE: Su... |
500 501 502 503 504 505 |
static int pim6_rcv(struct sk_buff *skb) { struct pimreghdr *pim; struct ipv6hdr *encap; struct net_device *reg_dev = NULL; |
8229efdae netns: ip6mr: ena... |
506 |
struct net *net = dev_net(skb->dev); |
b70432f73 mroute*: Make mr_... |
507 |
struct mr_table *mrt; |
4c9483b2f ipv6: Convert to ... |
508 509 510 |
struct flowi6 fl6 = { .flowi6_iif = skb->dev->ifindex, .flowi6_mark = skb->mark, |
d1db275dd ipv6: ip6mr: supp... |
511 512 |
}; int reg_vif_num; |
14fb64e1f [IPV6] MROUTE: Su... |
513 514 515 516 517 |
if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) goto drop; pim = (struct pimreghdr *)skb_transport_header(skb); |
56245cae1 net: pim: add all... |
518 |
if (pim->type != ((PIM_VERSION << 4) | PIM_TYPE_REGISTER) || |
14fb64e1f [IPV6] MROUTE: Su... |
519 |
(pim->flags & PIM_NULL_REGISTER) || |
1d6e55f19 IPv6: Fix multica... |
520 521 522 |
(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, sizeof(*pim), IPPROTO_PIM, csum_partial((void *)pim, sizeof(*pim), 0)) && |
ec6b486fa ipv6: result of c... |
523 |
csum_fold(skb_checksum(skb, 0, skb->len, 0)))) |
14fb64e1f [IPV6] MROUTE: Su... |
524 525 526 527 528 529 530 531 532 533 |
goto drop; /* check if the inner packet is destined to mcast group */ encap = (struct ipv6hdr *)(skb_transport_header(skb) + sizeof(*pim)); if (!ipv6_addr_is_multicast(&encap->daddr) || encap->payload_len == 0 || ntohs(encap->payload_len) + sizeof(*pim) > skb->len) goto drop; |
4c9483b2f ipv6: Convert to ... |
534 |
if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0) |
d1db275dd ipv6: ip6mr: supp... |
535 536 |
goto drop; reg_vif_num = mrt->mroute_reg_vif_num; |
14fb64e1f [IPV6] MROUTE: Su... |
537 538 |
read_lock(&mrt_lock); if (reg_vif_num >= 0) |
b70432f73 mroute*: Make mr_... |
539 |
reg_dev = mrt->vif_table[reg_vif_num].dev; |
14fb64e1f [IPV6] MROUTE: Su... |
540 541 542 |
if (reg_dev) dev_hold(reg_dev); read_unlock(&mrt_lock); |
63159f29b ipv6: coding styl... |
543 |
if (!reg_dev) |
14fb64e1f [IPV6] MROUTE: Su... |
544 545 546 547 548 |
goto drop; skb->mac_header = skb->network_header; skb_pull(skb, (u8 *)encap - skb->data); skb_reset_network_header(skb); |
1d6e55f19 IPv6: Fix multica... |
549 |
skb->protocol = htons(ETH_P_IPV6); |
3e49e6d52 net: use CHECKSUM... |
550 |
skb->ip_summed = CHECKSUM_NONE; |
d19d56ddc net: Introduce sk... |
551 |
|
ea23192e8 tunnels: harmoniz... |
552 |
skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev)); |
d19d56ddc net: Introduce sk... |
553 |
|
caf586e5f net: add a core n... |
554 |
netif_rx(skb); |
8990f468a net: rx_dropped a... |
555 |
|
14fb64e1f [IPV6] MROUTE: Su... |
556 557 558 559 560 561 |
dev_put(reg_dev); return 0; drop: kfree_skb(skb); return 0; } |
41135cc83 net: constify str... |
562 |
static const struct inet6_protocol pim6_protocol = { |
14fb64e1f [IPV6] MROUTE: Su... |
563 564 565 566 |
.handler = pim6_rcv, }; /* Service routines creating virtual interfaces: PIMREG */ |
6fef4c0c8 netdev: convert p... |
567 568 |
static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) |
14fb64e1f [IPV6] MROUTE: Su... |
569 |
{ |
8229efdae netns: ip6mr: ena... |
570 |
struct net *net = dev_net(dev); |
b70432f73 mroute*: Make mr_... |
571 |
struct mr_table *mrt; |
4c9483b2f ipv6: Convert to ... |
572 573 |
struct flowi6 fl6 = { .flowi6_oif = dev->ifindex, |
6a662719c ipv4, fib: pass L... |
574 |
.flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX, |
4c9483b2f ipv6: Convert to ... |
575 |
.flowi6_mark = skb->mark, |
d1db275dd ipv6: ip6mr: supp... |
576 |
}; |
d1db275dd ipv6: ip6mr: supp... |
577 |
|
cb9f1b783 ip: validate head... |
578 579 580 581 582 |
if (!pskb_inet_may_pull(skb)) goto tx_err; if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0) goto tx_err; |
8229efdae netns: ip6mr: ena... |
583 |
|
14fb64e1f [IPV6] MROUTE: Su... |
584 |
read_lock(&mrt_lock); |
dc58c78c0 ip6mr: Use on-dev... |
585 586 |
dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; |
6bd521433 ipv6: ip6mr: move... |
587 |
ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT); |
14fb64e1f [IPV6] MROUTE: Su... |
588 589 |
read_unlock(&mrt_lock); kfree_skb(skb); |
6ed106549 net: use NETDEV_T... |
590 |
return NETDEV_TX_OK; |
cb9f1b783 ip: validate head... |
591 592 593 594 595 |
tx_err: dev->stats.tx_errors++; kfree_skb(skb); return NETDEV_TX_OK; |
14fb64e1f [IPV6] MROUTE: Su... |
596 |
} |
ee9b9596a ipmr,ip6mr: imple... |
597 598 599 600 |
static int reg_vif_get_iflink(const struct net_device *dev) { return 0; } |
007c3838d ipmr: convert ipm... |
601 602 |
static const struct net_device_ops reg_vif_netdev_ops = { .ndo_start_xmit = reg_vif_xmit, |
ee9b9596a ipmr,ip6mr: imple... |
603 |
.ndo_get_iflink = reg_vif_get_iflink, |
007c3838d ipmr: convert ipm... |
604 |
}; |
14fb64e1f [IPV6] MROUTE: Su... |
605 606 607 608 609 |
static void reg_vif_setup(struct net_device *dev) { dev->type = ARPHRD_PIMREG; dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8; dev->flags = IFF_NOARP; |
007c3838d ipmr: convert ipm... |
610 |
dev->netdev_ops = ®_vif_netdev_ops; |
cf124db56 net: Fix inconsis... |
611 |
dev->needs_free_netdev = true; |
403dbb97f PIM-SM: namespace... |
612 |
dev->features |= NETIF_F_NETNS_LOCAL; |
14fb64e1f [IPV6] MROUTE: Su... |
613 |
} |
b70432f73 mroute*: Make mr_... |
614 |
static struct net_device *ip6mr_reg_vif(struct net *net, struct mr_table *mrt) |
14fb64e1f [IPV6] MROUTE: Su... |
615 616 |
{ struct net_device *dev; |
d1db275dd ipv6: ip6mr: supp... |
617 618 619 620 621 622 |
char name[IFNAMSIZ]; if (mrt->id == RT6_TABLE_DFLT) sprintf(name, "pim6reg"); else sprintf(name, "pim6reg%u", mrt->id); |
14fb64e1f [IPV6] MROUTE: Su... |
623 |
|
c835a6773 net: set name_ass... |
624 |
dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup); |
63159f29b ipv6: coding styl... |
625 |
if (!dev) |
14fb64e1f [IPV6] MROUTE: Su... |
626 |
return NULL; |
8229efdae netns: ip6mr: ena... |
627 |
dev_net_set(dev, net); |
14fb64e1f [IPV6] MROUTE: Su... |
628 629 630 631 |
if (register_netdevice(dev)) { free_netdev(dev); return NULL; } |
14fb64e1f [IPV6] MROUTE: Su... |
632 |
|
00f54e689 net: core: dev: A... |
633 |
if (dev_open(dev, NULL)) |
14fb64e1f [IPV6] MROUTE: Su... |
634 |
goto failure; |
7af3db78a ipv6: Fix using a... |
635 |
dev_hold(dev); |
14fb64e1f [IPV6] MROUTE: Su... |
636 637 638 |
return dev; failure: |
14fb64e1f [IPV6] MROUTE: Su... |
639 640 641 642 |
unregister_netdevice(dev); return NULL; } #endif |
088aa3eec ip6mr: Support fi... |
643 644 645 646 647 648 649 650 651 |
static int call_ip6mr_vif_entry_notifiers(struct net *net, enum fib_event_type event_type, struct vif_device *vif, mifi_t vif_index, u32 tb_id) { return mr_call_vif_notifiers(net, RTNL_FAMILY_IP6MR, event_type, vif, vif_index, tb_id, &net->ipv6.ipmr_seq); } |
7bc570c8b [IPV6] MROUTE: Su... |
652 |
|
088aa3eec ip6mr: Support fi... |
653 654 655 656 657 658 659 660 661 |
static int call_ip6mr_mfc_entry_notifiers(struct net *net, enum fib_event_type event_type, struct mfc6_cache *mfc, u32 tb_id) { return mr_call_mfc_notifiers(net, RTNL_FAMILY_IP6MR, event_type, &mfc->_c, tb_id, &net->ipv6.ipmr_seq); } /* Delete a VIF entry */ |
b70432f73 mroute*: Make mr_... |
662 |
static int mif6_delete(struct mr_table *mrt, int vifi, int notify, |
723b929ca ip6mr: fix notifi... |
663 |
struct list_head *head) |
7bc570c8b [IPV6] MROUTE: Su... |
664 |
{ |
6853f21f7 ipmr,ipmr6: Defin... |
665 |
struct vif_device *v; |
7bc570c8b [IPV6] MROUTE: Su... |
666 |
struct net_device *dev; |
1d6e55f19 IPv6: Fix multica... |
667 |
struct inet6_dev *in6_dev; |
6bd521433 ipv6: ip6mr: move... |
668 669 |
if (vifi < 0 || vifi >= mrt->maxvif) |
7bc570c8b [IPV6] MROUTE: Su... |
670 |
return -EADDRNOTAVAIL; |
b70432f73 mroute*: Make mr_... |
671 |
v = &mrt->vif_table[vifi]; |
7bc570c8b [IPV6] MROUTE: Su... |
672 |
|
088aa3eec ip6mr: Support fi... |
673 674 675 676 |
if (VIF_EXISTS(mrt, vifi)) call_ip6mr_vif_entry_notifiers(read_pnet(&mrt->net), FIB_EVENT_VIF_DEL, v, vifi, mrt->id); |
7bc570c8b [IPV6] MROUTE: Su... |
677 678 679 680 681 682 683 684 |
write_lock_bh(&mrt_lock); dev = v->dev; v->dev = NULL; if (!dev) { write_unlock_bh(&mrt_lock); return -EADDRNOTAVAIL; } |
14fb64e1f [IPV6] MROUTE: Su... |
685 |
#ifdef CONFIG_IPV6_PIMSM_V2 |
6bd521433 ipv6: ip6mr: move... |
686 687 |
if (vifi == mrt->mroute_reg_vif_num) mrt->mroute_reg_vif_num = -1; |
14fb64e1f [IPV6] MROUTE: Su... |
688 |
#endif |
6bd521433 ipv6: ip6mr: move... |
689 |
if (vifi + 1 == mrt->maxvif) { |
7bc570c8b [IPV6] MROUTE: Su... |
690 691 |
int tmp; for (tmp = vifi - 1; tmp >= 0; tmp--) { |
b70432f73 mroute*: Make mr_... |
692 |
if (VIF_EXISTS(mrt, tmp)) |
7bc570c8b [IPV6] MROUTE: Su... |
693 694 |
break; } |
6bd521433 ipv6: ip6mr: move... |
695 |
mrt->maxvif = tmp + 1; |
7bc570c8b [IPV6] MROUTE: Su... |
696 697 698 699 700 |
} write_unlock_bh(&mrt_lock); dev_set_allmulti(dev, -1); |
1d6e55f19 IPv6: Fix multica... |
701 |
in6_dev = __in6_dev_get(dev); |
d67b8c616 netconf: advertis... |
702 |
if (in6_dev) { |
1d6e55f19 IPv6: Fix multica... |
703 |
in6_dev->cnf.mc_forwarding--; |
85b3daada net: ipv6: Refact... |
704 |
inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, |
d67b8c616 netconf: advertis... |
705 706 707 |
NETCONFA_MC_FORWARDING, dev->ifindex, &in6_dev->cnf); } |
1d6e55f19 IPv6: Fix multica... |
708 |
|
723b929ca ip6mr: fix notifi... |
709 |
if ((v->flags & MIFF_REGISTER) && !notify) |
c871e664e ip6mr: Optimize m... |
710 |
unregister_netdevice_queue(dev, head); |
7bc570c8b [IPV6] MROUTE: Su... |
711 712 713 714 |
dev_put(dev); return 0; } |
87c418bf1 ip6mr: Align hash... |
715 |
static inline void ip6mr_cache_free_rcu(struct rcu_head *head) |
58701ad41 netns: ip6mr: sto... |
716 |
{ |
494fff563 ipmr, ip6mr: Make... |
717 |
struct mr_mfc *c = container_of(head, struct mr_mfc, rcu); |
87c418bf1 ip6mr: Align hash... |
718 |
|
494fff563 ipmr, ip6mr: Make... |
719 |
kmem_cache_free(mrt_cachep, (struct mfc6_cache *)c); |
58701ad41 netns: ip6mr: sto... |
720 |
} |
87c418bf1 ip6mr: Align hash... |
721 722 |
static inline void ip6mr_cache_free(struct mfc6_cache *c) { |
494fff563 ipmr, ip6mr: Make... |
723 |
call_rcu(&c->_c.rcu, ip6mr_cache_free_rcu); |
87c418bf1 ip6mr: Align hash... |
724 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
725 726 727 |
/* Destroy an unresolved cache entry, killing queued skbs and reporting error to netlink readers. */ |
b70432f73 mroute*: Make mr_... |
728 |
static void ip6mr_destroy_unres(struct mr_table *mrt, struct mfc6_cache *c) |
7bc570c8b [IPV6] MROUTE: Su... |
729 |
{ |
6bd521433 ipv6: ip6mr: move... |
730 |
struct net *net = read_pnet(&mrt->net); |
7bc570c8b [IPV6] MROUTE: Su... |
731 |
struct sk_buff *skb; |
6bd521433 ipv6: ip6mr: move... |
732 |
atomic_dec(&mrt->cache_resolve_queue_len); |
7bc570c8b [IPV6] MROUTE: Su... |
733 |
|
494fff563 ipmr, ip6mr: Make... |
734 |
while ((skb = skb_dequeue(&c->_c.mfc_un.unres.unresolved)) != NULL) { |
7bc570c8b [IPV6] MROUTE: Su... |
735 |
if (ipv6_hdr(skb)->version == 0) { |
af72868b9 networking: make ... |
736 737 |
struct nlmsghdr *nlh = skb_pull(skb, sizeof(struct ipv6hdr)); |
7bc570c8b [IPV6] MROUTE: Su... |
738 |
nlh->nlmsg_type = NLMSG_ERROR; |
573ce260b net-next: replace... |
739 |
nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr)); |
7bc570c8b [IPV6] MROUTE: Su... |
740 |
skb_trim(skb, nlh->nlmsg_len); |
573ce260b net-next: replace... |
741 |
((struct nlmsgerr *)nlmsg_data(nlh))->error = -ETIMEDOUT; |
15e473046 netlink: Rename p... |
742 |
rtnl_unicast(skb, net, NETLINK_CB(skb).portid); |
7bc570c8b [IPV6] MROUTE: Su... |
743 744 745 |
} else kfree_skb(skb); } |
58701ad41 netns: ip6mr: sto... |
746 |
ip6mr_cache_free(c); |
7bc570c8b [IPV6] MROUTE: Su... |
747 |
} |
c476efbcd ipv6: ip6mr: move... |
748 |
/* Timer process for all the unresolved queue. */ |
7bc570c8b [IPV6] MROUTE: Su... |
749 |
|
b70432f73 mroute*: Make mr_... |
750 |
static void ipmr_do_expire_process(struct mr_table *mrt) |
7bc570c8b [IPV6] MROUTE: Su... |
751 752 753 |
{ unsigned long now = jiffies; unsigned long expires = 10 * HZ; |
494fff563 ipmr, ip6mr: Make... |
754 |
struct mr_mfc *c, *next; |
7bc570c8b [IPV6] MROUTE: Su... |
755 |
|
b70432f73 mroute*: Make mr_... |
756 |
list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) { |
7bc570c8b [IPV6] MROUTE: Su... |
757 758 759 760 761 |
if (time_after(c->mfc_un.unres.expires, now)) { /* not yet... */ unsigned long interval = c->mfc_un.unres.expires - now; if (interval < expires) expires = interval; |
7bc570c8b [IPV6] MROUTE: Su... |
762 763 |
continue; } |
f30a77842 ipv6: ip6mr: conv... |
764 |
list_del(&c->list); |
494fff563 ipmr, ip6mr: Make... |
765 766 |
mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); |
7bc570c8b [IPV6] MROUTE: Su... |
767 |
} |
b70432f73 mroute*: Make mr_... |
768 |
if (!list_empty(&mrt->mfc_unres_queue)) |
6bd521433 ipv6: ip6mr: move... |
769 |
mod_timer(&mrt->ipmr_expire_timer, jiffies + expires); |
7bc570c8b [IPV6] MROUTE: Su... |
770 |
} |
e99e88a9d treewide: setup_t... |
771 |
static void ipmr_expire_process(struct timer_list *t) |
7bc570c8b [IPV6] MROUTE: Su... |
772 |
{ |
b70432f73 mroute*: Make mr_... |
773 |
struct mr_table *mrt = from_timer(mrt, t, ipmr_expire_timer); |
c476efbcd ipv6: ip6mr: move... |
774 |
|
7bc570c8b [IPV6] MROUTE: Su... |
775 |
if (!spin_trylock(&mfc_unres_lock)) { |
6bd521433 ipv6: ip6mr: move... |
776 |
mod_timer(&mrt->ipmr_expire_timer, jiffies + 1); |
7bc570c8b [IPV6] MROUTE: Su... |
777 778 |
return; } |
b70432f73 mroute*: Make mr_... |
779 |
if (!list_empty(&mrt->mfc_unres_queue)) |
6bd521433 ipv6: ip6mr: move... |
780 |
ipmr_do_expire_process(mrt); |
7bc570c8b [IPV6] MROUTE: Su... |
781 782 783 784 785 |
spin_unlock(&mfc_unres_lock); } /* Fill oifs list. It is called under write locked mrt_lock. */ |
b70432f73 mroute*: Make mr_... |
786 |
static void ip6mr_update_thresholds(struct mr_table *mrt, |
494fff563 ipmr, ip6mr: Make... |
787 |
struct mr_mfc *cache, |
b5aa30b19 ipv6: ip6mr: remo... |
788 |
unsigned char *ttls) |
7bc570c8b [IPV6] MROUTE: Su... |
789 790 |
{ int vifi; |
6ac7eb086 [IPV6] MROUTE: Ad... |
791 |
cache->mfc_un.res.minvif = MAXMIFS; |
7bc570c8b [IPV6] MROUTE: Su... |
792 |
cache->mfc_un.res.maxvif = 0; |
6ac7eb086 [IPV6] MROUTE: Ad... |
793 |
memset(cache->mfc_un.res.ttls, 255, MAXMIFS); |
7bc570c8b [IPV6] MROUTE: Su... |
794 |
|
6bd521433 ipv6: ip6mr: move... |
795 |
for (vifi = 0; vifi < mrt->maxvif; vifi++) { |
b70432f73 mroute*: Make mr_... |
796 |
if (VIF_EXISTS(mrt, vifi) && |
4e16880cb netns: ip6mr: dyn... |
797 |
ttls[vifi] && ttls[vifi] < 255) { |
7bc570c8b [IPV6] MROUTE: Su... |
798 799 800 801 802 803 804 |
cache->mfc_un.res.ttls[vifi] = ttls[vifi]; if (cache->mfc_un.res.minvif > vifi) cache->mfc_un.res.minvif = vifi; if (cache->mfc_un.res.maxvif <= vifi) cache->mfc_un.res.maxvif = vifi + 1; } } |
90b5ca176 net: ipmr/ip6mr: ... |
805 |
cache->mfc_un.res.lastuse = jiffies; |
7bc570c8b [IPV6] MROUTE: Su... |
806 |
} |
b70432f73 mroute*: Make mr_... |
807 |
static int mif6_add(struct net *net, struct mr_table *mrt, |
6bd521433 ipv6: ip6mr: move... |
808 |
struct mif6ctl *vifc, int mrtsock) |
7bc570c8b [IPV6] MROUTE: Su... |
809 810 |
{ int vifi = vifc->mif6c_mifi; |
b70432f73 mroute*: Make mr_... |
811 |
struct vif_device *v = &mrt->vif_table[vifi]; |
7bc570c8b [IPV6] MROUTE: Su... |
812 |
struct net_device *dev; |
1d6e55f19 IPv6: Fix multica... |
813 |
struct inet6_dev *in6_dev; |
5ae7b4441 ipv6: Check retur... |
814 |
int err; |
7bc570c8b [IPV6] MROUTE: Su... |
815 816 |
/* Is vif busy ? */ |
b70432f73 mroute*: Make mr_... |
817 |
if (VIF_EXISTS(mrt, vifi)) |
7bc570c8b [IPV6] MROUTE: Su... |
818 819 820 |
return -EADDRINUSE; switch (vifc->mif6c_flags) { |
14fb64e1f [IPV6] MROUTE: Su... |
821 822 823 824 825 826 |
#ifdef CONFIG_IPV6_PIMSM_V2 case MIFF_REGISTER: /* * Special Purpose VIF in PIM * All the packets will be sent to the daemon */ |
6bd521433 ipv6: ip6mr: move... |
827 |
if (mrt->mroute_reg_vif_num >= 0) |
14fb64e1f [IPV6] MROUTE: Su... |
828 |
return -EADDRINUSE; |
d1db275dd ipv6: ip6mr: supp... |
829 |
dev = ip6mr_reg_vif(net, mrt); |
14fb64e1f [IPV6] MROUTE: Su... |
830 831 |
if (!dev) return -ENOBUFS; |
5ae7b4441 ipv6: Check retur... |
832 833 834 |
err = dev_set_allmulti(dev, 1); if (err) { unregister_netdevice(dev); |
7af3db78a ipv6: Fix using a... |
835 |
dev_put(dev); |
5ae7b4441 ipv6: Check retur... |
836 837 |
return err; } |
14fb64e1f [IPV6] MROUTE: Su... |
838 839 |
break; #endif |
7bc570c8b [IPV6] MROUTE: Su... |
840 |
case 0: |
8229efdae netns: ip6mr: ena... |
841 |
dev = dev_get_by_index(net, vifc->mif6c_pifi); |
7bc570c8b [IPV6] MROUTE: Su... |
842 843 |
if (!dev) return -EADDRNOTAVAIL; |
5ae7b4441 ipv6: Check retur... |
844 |
err = dev_set_allmulti(dev, 1); |
7af3db78a ipv6: Fix using a... |
845 846 |
if (err) { dev_put(dev); |
5ae7b4441 ipv6: Check retur... |
847 |
return err; |
7af3db78a ipv6: Fix using a... |
848 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
849 850 851 852 |
break; default: return -EINVAL; } |
1d6e55f19 IPv6: Fix multica... |
853 |
in6_dev = __in6_dev_get(dev); |
d67b8c616 netconf: advertis... |
854 |
if (in6_dev) { |
1d6e55f19 IPv6: Fix multica... |
855 |
in6_dev->cnf.mc_forwarding++; |
85b3daada net: ipv6: Refact... |
856 |
inet6_netconf_notify_devconf(dev_net(dev), RTM_NEWNETCONF, |
d67b8c616 netconf: advertis... |
857 858 859 |
NETCONFA_MC_FORWARDING, dev->ifindex, &in6_dev->cnf); } |
1d6e55f19 IPv6: Fix multica... |
860 |
|
6853f21f7 ipmr,ipmr6: Defin... |
861 862 863 864 |
/* Fill in the VIF structures */ vif_device_init(v, dev, vifc->vifc_rate_limit, vifc->vifc_threshold, vifc->mif6c_flags | (!mrtsock ? VIFF_STATIC : 0), MIFF_REGISTER); |
7bc570c8b [IPV6] MROUTE: Su... |
865 866 867 |
/* And finish update writing critical data */ write_lock_bh(&mrt_lock); |
7bc570c8b [IPV6] MROUTE: Su... |
868 |
v->dev = dev; |
14fb64e1f [IPV6] MROUTE: Su... |
869 870 |
#ifdef CONFIG_IPV6_PIMSM_V2 if (v->flags & MIFF_REGISTER) |
6bd521433 ipv6: ip6mr: move... |
871 |
mrt->mroute_reg_vif_num = vifi; |
14fb64e1f [IPV6] MROUTE: Su... |
872 |
#endif |
6bd521433 ipv6: ip6mr: move... |
873 874 |
if (vifi + 1 > mrt->maxvif) mrt->maxvif = vifi + 1; |
7bc570c8b [IPV6] MROUTE: Su... |
875 |
write_unlock_bh(&mrt_lock); |
088aa3eec ip6mr: Support fi... |
876 877 |
call_ip6mr_vif_entry_notifiers(net, FIB_EVENT_VIF_ADD, v, vifi, mrt->id); |
7bc570c8b [IPV6] MROUTE: Su... |
878 879 |
return 0; } |
b70432f73 mroute*: Make mr_... |
880 |
static struct mfc6_cache *ip6mr_cache_find(struct mr_table *mrt, |
b71d1d426 inet: constify ip... |
881 882 |
const struct in6_addr *origin, const struct in6_addr *mcastgrp) |
7bc570c8b [IPV6] MROUTE: Su... |
883 |
{ |
87c418bf1 ip6mr: Align hash... |
884 885 886 887 |
struct mfc6_cache_cmp_arg arg = { .mf6c_origin = *origin, .mf6c_mcastgrp = *mcastgrp, }; |
87c418bf1 ip6mr: Align hash... |
888 |
|
845c9a7ae ipmr, ip6mr: Unit... |
889 |
return mr_mfc_find(mrt, &arg); |
660b26dc1 mcast: add multic... |
890 891 892 |
} /* Look for a (*,G) entry */ |
b70432f73 mroute*: Make mr_... |
893 |
static struct mfc6_cache *ip6mr_cache_find_any(struct mr_table *mrt, |
660b26dc1 mcast: add multic... |
894 895 896 |
struct in6_addr *mcastgrp, mifi_t mifi) { |
87c418bf1 ip6mr: Align hash... |
897 898 899 900 |
struct mfc6_cache_cmp_arg arg = { .mf6c_origin = in6addr_any, .mf6c_mcastgrp = *mcastgrp, }; |
660b26dc1 mcast: add multic... |
901 902 |
if (ipv6_addr_any(mcastgrp)) |
845c9a7ae ipmr, ip6mr: Unit... |
903 904 |
return mr_mfc_find_any_parent(mrt, mifi); return mr_mfc_find_any(mrt, mifi, &arg); |
660b26dc1 mcast: add multic... |
905 |
} |
87c418bf1 ip6mr: Align hash... |
906 907 |
/* Look for a (S,G,iif) entry if parent != -1 */ static struct mfc6_cache * |
b70432f73 mroute*: Make mr_... |
908 |
ip6mr_cache_find_parent(struct mr_table *mrt, |
87c418bf1 ip6mr: Align hash... |
909 910 911 912 913 914 915 916 |
const struct in6_addr *origin, const struct in6_addr *mcastgrp, int parent) { struct mfc6_cache_cmp_arg arg = { .mf6c_origin = *origin, .mf6c_mcastgrp = *mcastgrp, }; |
87c418bf1 ip6mr: Align hash... |
917 |
|
845c9a7ae ipmr, ip6mr: Unit... |
918 |
return mr_mfc_find_parent(mrt, &arg, parent); |
87c418bf1 ip6mr: Align hash... |
919 |
} |
845c9a7ae ipmr, ip6mr: Unit... |
920 |
/* Allocate a multicast cache entry */ |
b5aa30b19 ipv6: ip6mr: remo... |
921 |
static struct mfc6_cache *ip6mr_cache_alloc(void) |
7bc570c8b [IPV6] MROUTE: Su... |
922 |
{ |
36cbac590 net/ipv6/ip6mr.c:... |
923 |
struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); |
63159f29b ipv6: coding styl... |
924 |
if (!c) |
7bc570c8b [IPV6] MROUTE: Su... |
925 |
return NULL; |
494fff563 ipmr, ip6mr: Make... |
926 927 |
c->_c.mfc_un.res.last_assert = jiffies - MFC_ASSERT_THRESH - 1; c->_c.mfc_un.res.minvif = MAXMIFS; |
8c13af2a2 ip6mr: Add refcou... |
928 929 |
c->_c.free = ip6mr_cache_free_rcu; refcount_set(&c->_c.mfc_un.res.refcount, 1); |
7bc570c8b [IPV6] MROUTE: Su... |
930 931 |
return c; } |
b5aa30b19 ipv6: ip6mr: remo... |
932 |
static struct mfc6_cache *ip6mr_cache_alloc_unres(void) |
7bc570c8b [IPV6] MROUTE: Su... |
933 |
{ |
36cbac590 net/ipv6/ip6mr.c:... |
934 |
struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC); |
63159f29b ipv6: coding styl... |
935 |
if (!c) |
7bc570c8b [IPV6] MROUTE: Su... |
936 |
return NULL; |
494fff563 ipmr, ip6mr: Make... |
937 938 |
skb_queue_head_init(&c->_c.mfc_un.unres.unresolved); c->_c.mfc_un.unres.expires = jiffies + 10 * HZ; |
7bc570c8b [IPV6] MROUTE: Su... |
939 940 941 942 943 944 |
return c; } /* * A cache entry has gone into a resolved state from queued */ |
b70432f73 mroute*: Make mr_... |
945 |
static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt, |
6bd521433 ipv6: ip6mr: move... |
946 |
struct mfc6_cache *uc, struct mfc6_cache *c) |
7bc570c8b [IPV6] MROUTE: Su... |
947 948 949 950 951 952 |
{ struct sk_buff *skb; /* * Play the pending entries through our router */ |
494fff563 ipmr, ip6mr: Make... |
953 |
while ((skb = __skb_dequeue(&uc->_c.mfc_un.unres.unresolved))) { |
7bc570c8b [IPV6] MROUTE: Su... |
954 |
if (ipv6_hdr(skb)->version == 0) { |
af72868b9 networking: make ... |
955 956 |
struct nlmsghdr *nlh = skb_pull(skb, sizeof(struct ipv6hdr)); |
7bc570c8b [IPV6] MROUTE: Su... |
957 |
|
7b0db8573 ipmr, ip6mr: Unit... |
958 959 |
if (mr_fill_mroute(mrt, skb, &c->_c, nlmsg_data(nlh)) > 0) { |
549e028d0 [IPV6] MROUTE: Us... |
960 |
nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; |
7bc570c8b [IPV6] MROUTE: Su... |
961 962 |
} else { nlh->nlmsg_type = NLMSG_ERROR; |
573ce260b net-next: replace... |
963 |
nlh->nlmsg_len = nlmsg_msg_size(sizeof(struct nlmsgerr)); |
7bc570c8b [IPV6] MROUTE: Su... |
964 |
skb_trim(skb, nlh->nlmsg_len); |
573ce260b net-next: replace... |
965 |
((struct nlmsgerr *)nlmsg_data(nlh))->error = -EMSGSIZE; |
7bc570c8b [IPV6] MROUTE: Su... |
966 |
} |
15e473046 netlink: Rename p... |
967 |
rtnl_unicast(skb, net, NETLINK_CB(skb).portid); |
7bc570c8b [IPV6] MROUTE: Su... |
968 |
} else |
e4a38c0c4 ipv6: add vrf tab... |
969 |
ip6_mr_forward(net, mrt, skb->dev, skb, c); |
7bc570c8b [IPV6] MROUTE: Su... |
970 971 972 973 |
} } /* |
dd12d15c9 ip6mr: add netlin... |
974 |
* Bounce a cache query up to pim6sd and netlink. |
7bc570c8b [IPV6] MROUTE: Su... |
975 976 977 |
* * Called under mrt_lock. */ |
b70432f73 mroute*: Make mr_... |
978 |
static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, |
6bd521433 ipv6: ip6mr: move... |
979 |
mifi_t mifi, int assert) |
7bc570c8b [IPV6] MROUTE: Su... |
980 |
{ |
8571ab479 ip6mr: Make mrout... |
981 |
struct sock *mroute6_sk; |
7bc570c8b [IPV6] MROUTE: Su... |
982 983 984 |
struct sk_buff *skb; struct mrt6msg *msg; int ret; |
14fb64e1f [IPV6] MROUTE: Su... |
985 986 987 988 989 990 991 |
#ifdef CONFIG_IPV6_PIMSM_V2 if (assert == MRT6MSG_WHOLEPKT) skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt) +sizeof(*msg)); else #endif skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); |
7bc570c8b [IPV6] MROUTE: Su... |
992 993 994 995 996 997 998 999 |
if (!skb) return -ENOBUFS; /* I suppose that internal messages * do not require checksums */ skb->ip_summed = CHECKSUM_UNNECESSARY; |
14fb64e1f [IPV6] MROUTE: Su... |
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 |
#ifdef CONFIG_IPV6_PIMSM_V2 if (assert == MRT6MSG_WHOLEPKT) { /* Ugly, but we have no choice with this interface. Duplicate old header, fix length etc. And all this only to mangle msg->im6_msgtype and to set msg->im6_mbz to "mbz" :-) */ skb_push(skb, -skb_network_offset(pkt)); skb_push(skb, sizeof(*msg)); skb_reset_transport_header(skb); msg = (struct mrt6msg *)skb_transport_header(skb); msg->im6_mbz = 0; msg->im6_msgtype = MRT6MSG_WHOLEPKT; |
6bd521433 ipv6: ip6mr: move... |
1014 |
msg->im6_mif = mrt->mroute_reg_vif_num; |
14fb64e1f [IPV6] MROUTE: Su... |
1015 |
msg->im6_pad = 0; |
4e3fd7a06 net: remove ipv6_... |
1016 1017 |
msg->im6_src = ipv6_hdr(pkt)->saddr; msg->im6_dst = ipv6_hdr(pkt)->daddr; |
14fb64e1f [IPV6] MROUTE: Su... |
1018 1019 1020 1021 1022 |
skb->ip_summed = CHECKSUM_UNNECESSARY; } else #endif { |
7bc570c8b [IPV6] MROUTE: Su... |
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 |
/* * Copy the IP header */ skb_put(skb, sizeof(struct ipv6hdr)); skb_reset_network_header(skb); skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr)); /* * Add our header */ skb_put(skb, sizeof(*msg)); skb_reset_transport_header(skb); msg = (struct mrt6msg *)skb_transport_header(skb); msg->im6_mbz = 0; msg->im6_msgtype = assert; |
6ac7eb086 [IPV6] MROUTE: Ad... |
1040 |
msg->im6_mif = mifi; |
7bc570c8b [IPV6] MROUTE: Su... |
1041 |
msg->im6_pad = 0; |
4e3fd7a06 net: remove ipv6_... |
1042 1043 |
msg->im6_src = ipv6_hdr(pkt)->saddr; msg->im6_dst = ipv6_hdr(pkt)->daddr; |
7bc570c8b [IPV6] MROUTE: Su... |
1044 |
|
adf30907d net: skb->dst acc... |
1045 |
skb_dst_set(skb, dst_clone(skb_dst(pkt))); |
7bc570c8b [IPV6] MROUTE: Su... |
1046 |
skb->ip_summed = CHECKSUM_UNNECESSARY; |
14fb64e1f [IPV6] MROUTE: Su... |
1047 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1048 |
|
8571ab479 ip6mr: Make mrout... |
1049 |
rcu_read_lock(); |
b70432f73 mroute*: Make mr_... |
1050 |
mroute6_sk = rcu_dereference(mrt->mroute_sk); |
8571ab479 ip6mr: Make mrout... |
1051 1052 |
if (!mroute6_sk) { rcu_read_unlock(); |
7bc570c8b [IPV6] MROUTE: Su... |
1053 1054 1055 |
kfree_skb(skb); return -EINVAL; } |
dd12d15c9 ip6mr: add netlin... |
1056 |
mrt6msg_netlink_event(mrt, skb); |
8571ab479 ip6mr: Make mrout... |
1057 1058 1059 |
/* Deliver to user space multicast routing algorithms */ ret = sock_queue_rcv_skb(mroute6_sk, skb); rcu_read_unlock(); |
bd91b8bf3 netns: ip6mr: all... |
1060 |
if (ret < 0) { |
e87cc4728 net: Convert net_... |
1061 1062 |
net_warn_ratelimited("mroute6: pending queue full, dropping entries "); |
7bc570c8b [IPV6] MROUTE: Su... |
1063 1064 1065 1066 1067 |
kfree_skb(skb); } return ret; } |
494fff563 ipmr, ip6mr: Make... |
1068 1069 |
/* Queue a packet for resolution. It gets locked cache entry! */ static int ip6mr_cache_unresolved(struct mr_table *mrt, mifi_t mifi, |
e4a38c0c4 ipv6: add vrf tab... |
1070 |
struct sk_buff *skb, struct net_device *dev) |
7bc570c8b [IPV6] MROUTE: Su... |
1071 |
{ |
494fff563 ipmr, ip6mr: Make... |
1072 |
struct mfc6_cache *c; |
f30a77842 ipv6: ip6mr: conv... |
1073 |
bool found = false; |
7bc570c8b [IPV6] MROUTE: Su... |
1074 |
int err; |
7bc570c8b [IPV6] MROUTE: Su... |
1075 1076 |
spin_lock_bh(&mfc_unres_lock); |
494fff563 ipmr, ip6mr: Make... |
1077 |
list_for_each_entry(c, &mrt->mfc_unres_queue, _c.list) { |
c476efbcd ipv6: ip6mr: move... |
1078 |
if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && |
f30a77842 ipv6: ip6mr: conv... |
1079 1080 |
ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) { found = true; |
7bc570c8b [IPV6] MROUTE: Su... |
1081 |
break; |
f30a77842 ipv6: ip6mr: conv... |
1082 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1083 |
} |
f30a77842 ipv6: ip6mr: conv... |
1084 |
if (!found) { |
7bc570c8b [IPV6] MROUTE: Su... |
1085 1086 1087 |
/* * Create a new entry if allowable */ |
0079ad8e8 ipmr: remove hard... |
1088 1089 |
c = ip6mr_cache_alloc_unres(); if (!c) { |
7bc570c8b [IPV6] MROUTE: Su... |
1090 1091 1092 1093 1094 |
spin_unlock_bh(&mfc_unres_lock); kfree_skb(skb); return -ENOBUFS; } |
494fff563 ipmr, ip6mr: Make... |
1095 1096 |
/* Fill in the new cache entry */ c->_c.mfc_parent = -1; |
7bc570c8b [IPV6] MROUTE: Su... |
1097 1098 1099 1100 1101 1102 |
c->mf6c_origin = ipv6_hdr(skb)->saddr; c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr; /* * Reflect first query at pim6sd */ |
6bd521433 ipv6: ip6mr: move... |
1103 |
err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE); |
8229efdae netns: ip6mr: ena... |
1104 |
if (err < 0) { |
7bc570c8b [IPV6] MROUTE: Su... |
1105 1106 1107 1108 |
/* If the report failed throw the cache entry out - Brad Parker */ spin_unlock_bh(&mfc_unres_lock); |
58701ad41 netns: ip6mr: sto... |
1109 |
ip6mr_cache_free(c); |
7bc570c8b [IPV6] MROUTE: Su... |
1110 1111 1112 |
kfree_skb(skb); return err; } |
6bd521433 ipv6: ip6mr: move... |
1113 |
atomic_inc(&mrt->cache_resolve_queue_len); |
494fff563 ipmr, ip6mr: Make... |
1114 |
list_add(&c->_c.list, &mrt->mfc_unres_queue); |
812e44dd1 ip6mr: advertise ... |
1115 |
mr6_netlink_event(mrt, c, RTM_NEWROUTE); |
7bc570c8b [IPV6] MROUTE: Su... |
1116 |
|
6bd521433 ipv6: ip6mr: move... |
1117 |
ipmr_do_expire_process(mrt); |
7bc570c8b [IPV6] MROUTE: Su... |
1118 |
} |
494fff563 ipmr, ip6mr: Make... |
1119 1120 |
/* See if we can append the packet */ if (c->_c.mfc_un.unres.unresolved.qlen > 3) { |
7bc570c8b [IPV6] MROUTE: Su... |
1121 1122 1123 |
kfree_skb(skb); err = -ENOBUFS; } else { |
e4a38c0c4 ipv6: add vrf tab... |
1124 1125 1126 1127 |
if (dev) { skb->dev = dev; skb->skb_iif = dev->ifindex; } |
494fff563 ipmr, ip6mr: Make... |
1128 |
skb_queue_tail(&c->_c.mfc_un.unres.unresolved, skb); |
7bc570c8b [IPV6] MROUTE: Su... |
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 |
err = 0; } spin_unlock_bh(&mfc_unres_lock); return err; } /* * MFC6 cache manipulation by user space */ |
b70432f73 mroute*: Make mr_... |
1139 |
static int ip6mr_mfc_delete(struct mr_table *mrt, struct mf6cctl *mfc, |
660b26dc1 mcast: add multic... |
1140 |
int parent) |
7bc570c8b [IPV6] MROUTE: Su... |
1141 |
{ |
87c418bf1 ip6mr: Align hash... |
1142 |
struct mfc6_cache *c; |
7bc570c8b [IPV6] MROUTE: Su... |
1143 |
|
87c418bf1 ip6mr: Align hash... |
1144 1145 1146 1147 1148 1149 1150 |
/* The entries are added/deleted only under RTNL */ rcu_read_lock(); c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr, &mfc->mf6cc_mcastgrp.sin6_addr, parent); rcu_read_unlock(); if (!c) return -ENOENT; |
494fff563 ipmr, ip6mr: Make... |
1151 1152 |
rhltable_remove(&mrt->mfc_hash, &c->_c.mnode, ip6mr_rht_params); list_del_rcu(&c->_c.list); |
7bc570c8b [IPV6] MROUTE: Su... |
1153 |
|
088aa3eec ip6mr: Support fi... |
1154 1155 |
call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), FIB_EVENT_ENTRY_DEL, c, mrt->id); |
87c418bf1 ip6mr: Align hash... |
1156 |
mr6_netlink_event(mrt, c, RTM_DELROUTE); |
8c13af2a2 ip6mr: Add refcou... |
1157 |
mr_cache_put(&c->_c); |
87c418bf1 ip6mr: Align hash... |
1158 |
return 0; |
7bc570c8b [IPV6] MROUTE: Su... |
1159 1160 1161 1162 1163 |
} static int ip6mr_device_event(struct notifier_block *this, unsigned long event, void *ptr) { |
351638e7d net: pass info st... |
1164 |
struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
8229efdae netns: ip6mr: ena... |
1165 |
struct net *net = dev_net(dev); |
b70432f73 mroute*: Make mr_... |
1166 |
struct mr_table *mrt; |
6853f21f7 ipmr,ipmr6: Defin... |
1167 |
struct vif_device *v; |
7bc570c8b [IPV6] MROUTE: Su... |
1168 |
int ct; |
7bc570c8b [IPV6] MROUTE: Su... |
1169 1170 |
if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; |
d1db275dd ipv6: ip6mr: supp... |
1171 |
ip6mr_for_each_table(mrt, net) { |
b70432f73 mroute*: Make mr_... |
1172 |
v = &mrt->vif_table[0]; |
d1db275dd ipv6: ip6mr: supp... |
1173 1174 |
for (ct = 0; ct < mrt->maxvif; ct++, v++) { if (v->dev == dev) |
723b929ca ip6mr: fix notifi... |
1175 |
mif6_delete(mrt, ct, 1, NULL); |
d1db275dd ipv6: ip6mr: supp... |
1176 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1177 |
} |
c871e664e ip6mr: Optimize m... |
1178 |
|
7bc570c8b [IPV6] MROUTE: Su... |
1179 1180 |
return NOTIFY_DONE; } |
088aa3eec ip6mr: Support fi... |
1181 1182 1183 1184 1185 1186 |
static unsigned int ip6mr_seq_read(struct net *net) { ASSERT_RTNL(); return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net); } |
b7a595577 net: fib_notifier... |
1187 1188 |
static int ip6mr_dump(struct net *net, struct notifier_block *nb, struct netlink_ext_ack *extack) |
088aa3eec ip6mr: Support fi... |
1189 1190 |
{ return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump, |
b7a595577 net: fib_notifier... |
1191 |
ip6mr_mr_table_iter, &mrt_lock, extack); |
088aa3eec ip6mr: Support fi... |
1192 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1193 1194 1195 |
static struct notifier_block ip6_mr_notifier = { .notifier_call = ip6mr_device_event }; |
088aa3eec ip6mr: Support fi... |
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 |
static const struct fib_notifier_ops ip6mr_notifier_ops_template = { .family = RTNL_FAMILY_IP6MR, .fib_seq_read = ip6mr_seq_read, .fib_dump = ip6mr_dump, .owner = THIS_MODULE, }; static int __net_init ip6mr_notifier_init(struct net *net) { struct fib_notifier_ops *ops; net->ipv6.ipmr_seq = 0; |
7bc570c8b [IPV6] MROUTE: Su... |
1208 |
|
088aa3eec ip6mr: Support fi... |
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
ops = fib_notifier_ops_register(&ip6mr_notifier_ops_template, net); if (IS_ERR(ops)) return PTR_ERR(ops); net->ipv6.ip6mr_notifier_ops = ops; return 0; } static void __net_exit ip6mr_notifier_exit(struct net *net) { fib_notifier_ops_unregister(net->ipv6.ip6mr_notifier_ops); net->ipv6.ip6mr_notifier_ops = NULL; } /* Setup for IP multicast routing */ |
4e16880cb netns: ip6mr: dyn... |
1225 1226 |
static int __net_init ip6mr_net_init(struct net *net) { |
d1db275dd ipv6: ip6mr: supp... |
1227 |
int err; |
f30a77842 ipv6: ip6mr: conv... |
1228 |
|
088aa3eec ip6mr: Support fi... |
1229 1230 1231 |
err = ip6mr_notifier_init(net); if (err) return err; |
d1db275dd ipv6: ip6mr: supp... |
1232 1233 |
err = ip6mr_rules_init(net); if (err < 0) |
088aa3eec ip6mr: Support fi... |
1234 |
goto ip6mr_rules_fail; |
8b90fc7e5 netns: ip6mr: dec... |
1235 1236 1237 |
#ifdef CONFIG_PROC_FS err = -ENOMEM; |
c35063722 proc: introduce p... |
1238 1239 |
if (!proc_create_net("ip6_mr_vif", 0, net->proc_net, &ip6mr_vif_seq_ops, sizeof(struct mr_vif_iter))) |
8b90fc7e5 netns: ip6mr: dec... |
1240 |
goto proc_vif_fail; |
c35063722 proc: introduce p... |
1241 1242 |
if (!proc_create_net("ip6_mr_cache", 0, net->proc_net, &ipmr_mfc_seq_ops, sizeof(struct mr_mfc_iter))) |
8b90fc7e5 netns: ip6mr: dec... |
1243 1244 |
goto proc_cache_fail; #endif |
6bd521433 ipv6: ip6mr: move... |
1245 |
|
4a6258a0e netns: ip6mr: dyn... |
1246 |
return 0; |
8b90fc7e5 netns: ip6mr: dec... |
1247 1248 |
#ifdef CONFIG_PROC_FS proc_cache_fail: |
ece31ffd5 net: proc: change... |
1249 |
remove_proc_entry("ip6_mr_vif", net->proc_net); |
8b90fc7e5 netns: ip6mr: dec... |
1250 |
proc_vif_fail: |
d1db275dd ipv6: ip6mr: supp... |
1251 |
ip6mr_rules_exit(net); |
8b90fc7e5 netns: ip6mr: dec... |
1252 |
#endif |
088aa3eec ip6mr: Support fi... |
1253 1254 |
ip6mr_rules_fail: ip6mr_notifier_exit(net); |
4e16880cb netns: ip6mr: dyn... |
1255 1256 1257 1258 1259 |
return err; } static void __net_exit ip6mr_net_exit(struct net *net) { |
8b90fc7e5 netns: ip6mr: dec... |
1260 |
#ifdef CONFIG_PROC_FS |
ece31ffd5 net: proc: change... |
1261 1262 |
remove_proc_entry("ip6_mr_cache", net->proc_net); remove_proc_entry("ip6_mr_vif", net->proc_net); |
8b90fc7e5 netns: ip6mr: dec... |
1263 |
#endif |
d1db275dd ipv6: ip6mr: supp... |
1264 |
ip6mr_rules_exit(net); |
088aa3eec ip6mr: Support fi... |
1265 |
ip6mr_notifier_exit(net); |
4e16880cb netns: ip6mr: dyn... |
1266 1267 1268 1269 1270 1271 |
} static struct pernet_operations ip6mr_net_ops = { .init = ip6mr_net_init, .exit = ip6mr_net_exit, }; |
623d1a1af ipv6: Do cleanup ... |
1272 |
int __init ip6_mr_init(void) |
7bc570c8b [IPV6] MROUTE: Su... |
1273 |
{ |
623d1a1af ipv6: Do cleanup ... |
1274 |
int err; |
7bc570c8b [IPV6] MROUTE: Su... |
1275 1276 1277 1278 1279 |
mrt_cachep = kmem_cache_create("ip6_mrt_cache", sizeof(struct mfc6_cache), 0, SLAB_HWCACHE_ALIGN, NULL); if (!mrt_cachep) |
623d1a1af ipv6: Do cleanup ... |
1280 |
return -ENOMEM; |
7bc570c8b [IPV6] MROUTE: Su... |
1281 |
|
4e16880cb netns: ip6mr: dyn... |
1282 1283 1284 |
err = register_pernet_subsys(&ip6mr_net_ops); if (err) goto reg_pernet_fail; |
623d1a1af ipv6: Do cleanup ... |
1285 1286 1287 |
err = register_netdevice_notifier(&ip6_mr_notifier); if (err) goto reg_notif_fail; |
403dbb97f PIM-SM: namespace... |
1288 1289 |
#ifdef CONFIG_IPV6_PIMSM_V2 if (inet6_add_protocol(&pim6_protocol, IPPROTO_PIM) < 0) { |
f32138319 net: ipv6: Standa... |
1290 1291 |
pr_err("%s: can't add PIM protocol ", __func__); |
403dbb97f PIM-SM: namespace... |
1292 1293 1294 1295 |
err = -EAGAIN; goto add_proto_fail; } #endif |
a3fde2add rtnetlink: ipv6: ... |
1296 1297 1298 1299 |
err = rtnl_register_module(THIS_MODULE, RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL, ip6mr_rtm_dumproute, 0); if (err == 0) return 0; |
403dbb97f PIM-SM: namespace... |
1300 |
#ifdef CONFIG_IPV6_PIMSM_V2 |
a3fde2add rtnetlink: ipv6: ... |
1301 |
inet6_del_protocol(&pim6_protocol, IPPROTO_PIM); |
403dbb97f PIM-SM: namespace... |
1302 1303 1304 |
add_proto_fail: unregister_netdevice_notifier(&ip6_mr_notifier); #endif |
87b30a653 ipv6: fix ip6_mr_... |
1305 |
reg_notif_fail: |
4e16880cb netns: ip6mr: dyn... |
1306 1307 |
unregister_pernet_subsys(&ip6mr_net_ops); reg_pernet_fail: |
87b30a653 ipv6: fix ip6_mr_... |
1308 |
kmem_cache_destroy(mrt_cachep); |
623d1a1af ipv6: Do cleanup ... |
1309 |
return err; |
7bc570c8b [IPV6] MROUTE: Su... |
1310 |
} |
623d1a1af ipv6: Do cleanup ... |
1311 1312 |
void ip6_mr_cleanup(void) { |
ffb1388a3 ipv6: delete prot... |
1313 1314 1315 1316 |
rtnl_unregister(RTNL_FAMILY_IP6MR, RTM_GETROUTE); #ifdef CONFIG_IPV6_PIMSM_V2 inet6_del_protocol(&pim6_protocol, IPPROTO_PIM); #endif |
623d1a1af ipv6: Do cleanup ... |
1317 |
unregister_netdevice_notifier(&ip6_mr_notifier); |
4e16880cb netns: ip6mr: dyn... |
1318 |
unregister_pernet_subsys(&ip6mr_net_ops); |
623d1a1af ipv6: Do cleanup ... |
1319 1320 |
kmem_cache_destroy(mrt_cachep); } |
7bc570c8b [IPV6] MROUTE: Su... |
1321 |
|
b70432f73 mroute*: Make mr_... |
1322 |
static int ip6mr_mfc_add(struct net *net, struct mr_table *mrt, |
660b26dc1 mcast: add multic... |
1323 |
struct mf6cctl *mfc, int mrtsock, int parent) |
7bc570c8b [IPV6] MROUTE: Su... |
1324 |
{ |
6ac7eb086 [IPV6] MROUTE: Ad... |
1325 |
unsigned char ttls[MAXMIFS]; |
87c418bf1 ip6mr: Align hash... |
1326 |
struct mfc6_cache *uc, *c; |
494fff563 ipmr, ip6mr: Make... |
1327 |
struct mr_mfc *_uc; |
87c418bf1 ip6mr: Align hash... |
1328 1329 |
bool found; int i, err; |
7bc570c8b [IPV6] MROUTE: Su... |
1330 |
|
a50436f2c net: ipmr/ip6mr: ... |
1331 1332 |
if (mfc->mf6cc_parent >= MAXMIFS) return -ENFILE; |
6ac7eb086 [IPV6] MROUTE: Ad... |
1333 1334 |
memset(ttls, 255, MAXMIFS); for (i = 0; i < MAXMIFS; i++) { |
7bc570c8b [IPV6] MROUTE: Su... |
1335 1336 |
if (IF_ISSET(i, &mfc->mf6cc_ifset)) ttls[i] = 1; |
7bc570c8b [IPV6] MROUTE: Su... |
1337 |
} |
87c418bf1 ip6mr: Align hash... |
1338 1339 1340 1341 1342 1343 |
/* The entries are added/deleted only under RTNL */ rcu_read_lock(); c = ip6mr_cache_find_parent(mrt, &mfc->mf6cc_origin.sin6_addr, &mfc->mf6cc_mcastgrp.sin6_addr, parent); rcu_read_unlock(); if (c) { |
7bc570c8b [IPV6] MROUTE: Su... |
1344 |
write_lock_bh(&mrt_lock); |
494fff563 ipmr, ip6mr: Make... |
1345 1346 |
c->_c.mfc_parent = mfc->mf6cc_parent; ip6mr_update_thresholds(mrt, &c->_c, ttls); |
7bc570c8b [IPV6] MROUTE: Su... |
1347 |
if (!mrtsock) |
494fff563 ipmr, ip6mr: Make... |
1348 |
c->_c.mfc_flags |= MFC_STATIC; |
7bc570c8b [IPV6] MROUTE: Su... |
1349 |
write_unlock_bh(&mrt_lock); |
088aa3eec ip6mr: Support fi... |
1350 1351 |
call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_REPLACE, c, mrt->id); |
812e44dd1 ip6mr: advertise ... |
1352 |
mr6_netlink_event(mrt, c, RTM_NEWROUTE); |
7bc570c8b [IPV6] MROUTE: Su... |
1353 1354 |
return 0; } |
660b26dc1 mcast: add multic... |
1355 1356 |
if (!ipv6_addr_any(&mfc->mf6cc_mcastgrp.sin6_addr) && !ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) |
7bc570c8b [IPV6] MROUTE: Su... |
1357 |
return -EINVAL; |
b5aa30b19 ipv6: ip6mr: remo... |
1358 |
c = ip6mr_cache_alloc(); |
63159f29b ipv6: coding styl... |
1359 |
if (!c) |
7bc570c8b [IPV6] MROUTE: Su... |
1360 1361 1362 1363 |
return -ENOMEM; c->mf6c_origin = mfc->mf6cc_origin.sin6_addr; c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr; |
494fff563 ipmr, ip6mr: Make... |
1364 1365 |
c->_c.mfc_parent = mfc->mf6cc_parent; ip6mr_update_thresholds(mrt, &c->_c, ttls); |
7bc570c8b [IPV6] MROUTE: Su... |
1366 |
if (!mrtsock) |
494fff563 ipmr, ip6mr: Make... |
1367 |
c->_c.mfc_flags |= MFC_STATIC; |
7bc570c8b [IPV6] MROUTE: Su... |
1368 |
|
494fff563 ipmr, ip6mr: Make... |
1369 |
err = rhltable_insert_key(&mrt->mfc_hash, &c->cmparg, &c->_c.mnode, |
87c418bf1 ip6mr: Align hash... |
1370 1371 1372 1373 1374 1375 1376 |
ip6mr_rht_params); if (err) { pr_err("ip6mr: rhtable insert error %d ", err); ip6mr_cache_free(c); return err; } |
494fff563 ipmr, ip6mr: Make... |
1377 |
list_add_tail_rcu(&c->_c.list, &mrt->mfc_cache_list); |
7bc570c8b [IPV6] MROUTE: Su... |
1378 |
|
87c418bf1 ip6mr: Align hash... |
1379 1380 |
/* Check to see if we resolved a queued list. If so we * need to send on the frames and tidy up. |
7bc570c8b [IPV6] MROUTE: Su... |
1381 |
*/ |
f30a77842 ipv6: ip6mr: conv... |
1382 |
found = false; |
7bc570c8b [IPV6] MROUTE: Su... |
1383 |
spin_lock_bh(&mfc_unres_lock); |
494fff563 ipmr, ip6mr: Make... |
1384 1385 |
list_for_each_entry(_uc, &mrt->mfc_unres_queue, list) { uc = (struct mfc6_cache *)_uc; |
c476efbcd ipv6: ip6mr: move... |
1386 |
if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && |
7bc570c8b [IPV6] MROUTE: Su... |
1387 |
ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) { |
494fff563 ipmr, ip6mr: Make... |
1388 |
list_del(&_uc->list); |
6bd521433 ipv6: ip6mr: move... |
1389 |
atomic_dec(&mrt->cache_resolve_queue_len); |
f30a77842 ipv6: ip6mr: conv... |
1390 |
found = true; |
7bc570c8b [IPV6] MROUTE: Su... |
1391 1392 1393 |
break; } } |
b70432f73 mroute*: Make mr_... |
1394 |
if (list_empty(&mrt->mfc_unres_queue)) |
6bd521433 ipv6: ip6mr: move... |
1395 |
del_timer(&mrt->ipmr_expire_timer); |
7bc570c8b [IPV6] MROUTE: Su... |
1396 |
spin_unlock_bh(&mfc_unres_lock); |
f30a77842 ipv6: ip6mr: conv... |
1397 |
if (found) { |
6bd521433 ipv6: ip6mr: move... |
1398 |
ip6mr_cache_resolve(net, mrt, uc, c); |
58701ad41 netns: ip6mr: sto... |
1399 |
ip6mr_cache_free(uc); |
7bc570c8b [IPV6] MROUTE: Su... |
1400 |
} |
088aa3eec ip6mr: Support fi... |
1401 1402 |
call_ip6mr_mfc_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, c, mrt->id); |
812e44dd1 ip6mr: advertise ... |
1403 |
mr6_netlink_event(mrt, c, RTM_NEWROUTE); |
7bc570c8b [IPV6] MROUTE: Su... |
1404 1405 1406 1407 1408 1409 |
return 0; } /* * Close the multicast socket, and clear the vif tables etc */ |
ca8d4794f ipmr: ip6mr: Crea... |
1410 |
static void mroute_clean_tables(struct mr_table *mrt, int flags) |
7bc570c8b [IPV6] MROUTE: Su... |
1411 |
{ |
494fff563 ipmr, ip6mr: Make... |
1412 |
struct mr_mfc *c, *tmp; |
c871e664e ip6mr: Optimize m... |
1413 |
LIST_HEAD(list); |
87c418bf1 ip6mr: Align hash... |
1414 |
int i; |
7bc570c8b [IPV6] MROUTE: Su... |
1415 |
|
87c418bf1 ip6mr: Align hash... |
1416 |
/* Shut down all active vif entries */ |
ca8d4794f ipmr: ip6mr: Crea... |
1417 1418 1419 1420 1421 1422 1423 1424 1425 |
if (flags & (MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC)) { for (i = 0; i < mrt->maxvif; i++) { if (((mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT6_FLUSH_MIFS_STATIC)) || (!(mrt->vif_table[i].flags & VIFF_STATIC) && !(flags & MRT6_FLUSH_MIFS))) continue; mif6_delete(mrt, i, 0, &list); } unregister_netdevice_many(&list); |
7bc570c8b [IPV6] MROUTE: Su... |
1426 |
} |
87c418bf1 ip6mr: Align hash... |
1427 |
/* Wipe the cache */ |
ca8d4794f ipmr: ip6mr: Crea... |
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 |
if (flags & (MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC)) { list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC_STATIC)) || (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT6_FLUSH_MFC))) continue; rhltable_remove(&mrt->mfc_hash, &c->mnode, ip6mr_rht_params); list_del_rcu(&c->list); call_ip6mr_mfc_entry_notifiers(read_pnet(&mrt->net), FIB_EVENT_ENTRY_DEL, (struct mfc6_cache *)c, mrt->id); mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); mr_cache_put(c); } |
7bc570c8b [IPV6] MROUTE: Su... |
1441 |
} |
ca8d4794f ipmr: ip6mr: Crea... |
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 |
if (flags & MRT6_FLUSH_MFC) { if (atomic_read(&mrt->cache_resolve_queue_len) != 0) { spin_lock_bh(&mfc_unres_lock); list_for_each_entry_safe(c, tmp, &mrt->mfc_unres_queue, list) { list_del(&c->list); mr6_netlink_event(mrt, (struct mfc6_cache *)c, RTM_DELROUTE); ip6mr_destroy_unres(mrt, (struct mfc6_cache *)c); } spin_unlock_bh(&mfc_unres_lock); |
7bc570c8b [IPV6] MROUTE: Su... |
1452 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1453 1454 |
} } |
b70432f73 mroute*: Make mr_... |
1455 |
static int ip6mr_sk_init(struct mr_table *mrt, struct sock *sk) |
7bc570c8b [IPV6] MROUTE: Su... |
1456 1457 |
{ int err = 0; |
8229efdae netns: ip6mr: ena... |
1458 |
struct net *net = sock_net(sk); |
7bc570c8b [IPV6] MROUTE: Su... |
1459 1460 1461 |
rtnl_lock(); write_lock_bh(&mrt_lock); |
b70432f73 mroute*: Make mr_... |
1462 |
if (rtnl_dereference(mrt->mroute_sk)) { |
7bc570c8b [IPV6] MROUTE: Su... |
1463 |
err = -EADDRINUSE; |
8571ab479 ip6mr: Make mrout... |
1464 |
} else { |
b70432f73 mroute*: Make mr_... |
1465 |
rcu_assign_pointer(mrt->mroute_sk, sk); |
a366e300a ip6mr: remove syn... |
1466 |
sock_set_flag(sk, SOCK_RCU_FREE); |
8571ab479 ip6mr: Make mrout... |
1467 |
net->ipv6.devconf_all->mc_forwarding++; |
927265bc6 ipv6: do not abus... |
1468 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1469 |
write_unlock_bh(&mrt_lock); |
927265bc6 ipv6: do not abus... |
1470 |
if (!err) |
85b3daada net: ipv6: Refact... |
1471 1472 |
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_MC_FORWARDING, |
927265bc6 ipv6: do not abus... |
1473 1474 |
NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all); |
7bc570c8b [IPV6] MROUTE: Su... |
1475 1476 1477 1478 1479 1480 1481 |
rtnl_unlock(); return err; } int ip6mr_sk_done(struct sock *sk) { |
d1db275dd ipv6: ip6mr: supp... |
1482 |
int err = -EACCES; |
8229efdae netns: ip6mr: ena... |
1483 |
struct net *net = sock_net(sk); |
b70432f73 mroute*: Make mr_... |
1484 |
struct mr_table *mrt; |
7bc570c8b [IPV6] MROUTE: Su... |
1485 |
|
338d182fa ipv6: try not to ... |
1486 1487 1488 |
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return err; |
7bc570c8b [IPV6] MROUTE: Su... |
1489 |
rtnl_lock(); |
d1db275dd ipv6: ip6mr: supp... |
1490 |
ip6mr_for_each_table(mrt, net) { |
b70432f73 mroute*: Make mr_... |
1491 |
if (sk == rtnl_dereference(mrt->mroute_sk)) { |
d1db275dd ipv6: ip6mr: supp... |
1492 |
write_lock_bh(&mrt_lock); |
b70432f73 mroute*: Make mr_... |
1493 |
RCU_INIT_POINTER(mrt->mroute_sk, NULL); |
a366e300a ip6mr: remove syn... |
1494 1495 1496 1497 |
/* Note that mroute_sk had SOCK_RCU_FREE set, * so the RCU grace period before sk freeing * is guaranteed by sk_destruct() */ |
d1db275dd ipv6: ip6mr: supp... |
1498 |
net->ipv6.devconf_all->mc_forwarding--; |
927265bc6 ipv6: do not abus... |
1499 |
write_unlock_bh(&mrt_lock); |
85b3daada net: ipv6: Refact... |
1500 |
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF, |
d67b8c616 netconf: advertis... |
1501 1502 1503 |
NETCONFA_MC_FORWARDING, NETCONFA_IFINDEX_ALL, net->ipv6.devconf_all); |
7bc570c8b [IPV6] MROUTE: Su... |
1504 |
|
ca8d4794f ipmr: ip6mr: Crea... |
1505 |
mroute_clean_tables(mrt, MRT6_FLUSH_MIFS | MRT6_FLUSH_MFC); |
d1db275dd ipv6: ip6mr: supp... |
1506 1507 1508 1509 |
err = 0; break; } } |
7bc570c8b [IPV6] MROUTE: Su... |
1510 1511 1512 1513 |
rtnl_unlock(); return err; } |
8571ab479 ip6mr: Make mrout... |
1514 |
bool mroute6_is_socket(struct net *net, struct sk_buff *skb) |
6bd521433 ipv6: ip6mr: move... |
1515 |
{ |
b70432f73 mroute*: Make mr_... |
1516 |
struct mr_table *mrt; |
4c9483b2f ipv6: Convert to ... |
1517 |
struct flowi6 fl6 = { |
e374c618b net: ipv6: more p... |
1518 |
.flowi6_iif = skb->skb_iif ? : LOOPBACK_IFINDEX, |
4c9483b2f ipv6: Convert to ... |
1519 1520 |
.flowi6_oif = skb->dev->ifindex, .flowi6_mark = skb->mark, |
d1db275dd ipv6: ip6mr: supp... |
1521 |
}; |
4c9483b2f ipv6: Convert to ... |
1522 |
if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0) |
d1db275dd ipv6: ip6mr: supp... |
1523 |
return NULL; |
6bd521433 ipv6: ip6mr: move... |
1524 |
|
b70432f73 mroute*: Make mr_... |
1525 |
return rcu_access_pointer(mrt->mroute_sk); |
6bd521433 ipv6: ip6mr: move... |
1526 |
} |
8571ab479 ip6mr: Make mrout... |
1527 |
EXPORT_SYMBOL(mroute6_is_socket); |
6bd521433 ipv6: ip6mr: move... |
1528 |
|
7bc570c8b [IPV6] MROUTE: Su... |
1529 1530 1531 1532 1533 1534 |
/* * Socket options and virtual interface manipulation. The whole * virtual interface system is a complete heap, but unfortunately * that's how BSD mrouted happens to think. Maybe one day with a proper * MOSPF/PIM router set up we can clean this up. */ |
b43c61531 net/ipv6: switch ... |
1535 1536 |
int ip6_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval, unsigned int optlen) |
7bc570c8b [IPV6] MROUTE: Su... |
1537 |
{ |
660b26dc1 mcast: add multic... |
1538 |
int ret, parent = 0; |
7bc570c8b [IPV6] MROUTE: Su... |
1539 1540 1541 |
struct mif6ctl vif; struct mf6cctl mfc; mifi_t mifi; |
8229efdae netns: ip6mr: ena... |
1542 |
struct net *net = sock_net(sk); |
b70432f73 mroute*: Make mr_... |
1543 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
1544 |
|
99253eb75 ipv6: check sk sk... |
1545 1546 1547 |
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; |
d1db275dd ipv6: ip6mr: supp... |
1548 |
mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
1549 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
1550 |
return -ENOENT; |
7bc570c8b [IPV6] MROUTE: Su... |
1551 1552 |
if (optname != MRT6_INIT) { |
b70432f73 mroute*: Make mr_... |
1553 |
if (sk != rcu_access_pointer(mrt->mroute_sk) && |
8571ab479 ip6mr: Make mrout... |
1554 |
!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
7bc570c8b [IPV6] MROUTE: Su... |
1555 1556 1557 1558 1559 |
return -EACCES; } switch (optname) { case MRT6_INIT: |
7bc570c8b [IPV6] MROUTE: Su... |
1560 1561 |
if (optlen < sizeof(int)) return -EINVAL; |
6bd521433 ipv6: ip6mr: move... |
1562 |
return ip6mr_sk_init(mrt, sk); |
7bc570c8b [IPV6] MROUTE: Su... |
1563 1564 1565 1566 1567 1568 1569 |
case MRT6_DONE: return ip6mr_sk_done(sk); case MRT6_ADD_MIF: if (optlen < sizeof(vif)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1570 |
if (copy_from_sockptr(&vif, optval, sizeof(vif))) |
7bc570c8b [IPV6] MROUTE: Su... |
1571 |
return -EFAULT; |
6ac7eb086 [IPV6] MROUTE: Ad... |
1572 |
if (vif.mif6c_mifi >= MAXMIFS) |
7bc570c8b [IPV6] MROUTE: Su... |
1573 1574 |
return -ENFILE; rtnl_lock(); |
8571ab479 ip6mr: Make mrout... |
1575 |
ret = mif6_add(net, mrt, &vif, |
b70432f73 mroute*: Make mr_... |
1576 |
sk == rtnl_dereference(mrt->mroute_sk)); |
7bc570c8b [IPV6] MROUTE: Su... |
1577 1578 1579 1580 1581 1582 |
rtnl_unlock(); return ret; case MRT6_DEL_MIF: if (optlen < sizeof(mifi_t)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1583 |
if (copy_from_sockptr(&mifi, optval, sizeof(mifi_t))) |
7bc570c8b [IPV6] MROUTE: Su... |
1584 1585 |
return -EFAULT; rtnl_lock(); |
723b929ca ip6mr: fix notifi... |
1586 |
ret = mif6_delete(mrt, mifi, 0, NULL); |
7bc570c8b [IPV6] MROUTE: Su... |
1587 1588 1589 1590 1591 1592 1593 1594 1595 |
rtnl_unlock(); return ret; /* * Manipulate the forwarding caches. These live * in a sort of kernel/user symbiosis. */ case MRT6_ADD_MFC: case MRT6_DEL_MFC: |
660b26dc1 mcast: add multic... |
1596 |
parent = -1; |
a8eceea84 inet: Use fallthr... |
1597 |
fallthrough; |
660b26dc1 mcast: add multic... |
1598 1599 |
case MRT6_ADD_MFC_PROXY: case MRT6_DEL_MFC_PROXY: |
7bc570c8b [IPV6] MROUTE: Su... |
1600 1601 |
if (optlen < sizeof(mfc)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1602 |
if (copy_from_sockptr(&mfc, optval, sizeof(mfc))) |
7bc570c8b [IPV6] MROUTE: Su... |
1603 |
return -EFAULT; |
660b26dc1 mcast: add multic... |
1604 1605 |
if (parent == 0) parent = mfc.mf6cc_parent; |
7bc570c8b [IPV6] MROUTE: Su... |
1606 |
rtnl_lock(); |
660b26dc1 mcast: add multic... |
1607 1608 |
if (optname == MRT6_DEL_MFC || optname == MRT6_DEL_MFC_PROXY) ret = ip6mr_mfc_delete(mrt, &mfc, parent); |
7bc570c8b [IPV6] MROUTE: Su... |
1609 |
else |
660b26dc1 mcast: add multic... |
1610 |
ret = ip6mr_mfc_add(net, mrt, &mfc, |
8571ab479 ip6mr: Make mrout... |
1611 |
sk == |
b70432f73 mroute*: Make mr_... |
1612 |
rtnl_dereference(mrt->mroute_sk), |
8571ab479 ip6mr: Make mrout... |
1613 |
parent); |
7bc570c8b [IPV6] MROUTE: Su... |
1614 1615 |
rtnl_unlock(); return ret; |
ca8d4794f ipmr: ip6mr: Crea... |
1616 1617 1618 1619 1620 1621 |
case MRT6_FLUSH: { int flags; if (optlen != sizeof(flags)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1622 |
if (copy_from_sockptr(&flags, optval, sizeof(flags))) |
ca8d4794f ipmr: ip6mr: Crea... |
1623 1624 1625 1626 1627 1628 |
return -EFAULT; rtnl_lock(); mroute_clean_tables(mrt, flags); rtnl_unlock(); return 0; } |
7bc570c8b [IPV6] MROUTE: Su... |
1629 |
/* |
14fb64e1f [IPV6] MROUTE: Su... |
1630 1631 1632 1633 1634 |
* Control PIM assert (to activate pim will activate assert) */ case MRT6_ASSERT: { int v; |
03f52a0a5 ip6mr: Add sizeof... |
1635 1636 1637 |
if (optlen != sizeof(v)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1638 |
if (copy_from_sockptr(&v, optval, sizeof(v))) |
14fb64e1f [IPV6] MROUTE: Su... |
1639 |
return -EFAULT; |
53d6841d2 ipv4/ipmr and ipv... |
1640 |
mrt->mroute_do_assert = v; |
14fb64e1f [IPV6] MROUTE: Su... |
1641 1642 1643 1644 1645 1646 |
return 0; } #ifdef CONFIG_IPV6_PIMSM_V2 case MRT6_PIM: { |
a9f83bf38 [IPV6]: Sparse: R... |
1647 |
int v; |
03f52a0a5 ip6mr: Add sizeof... |
1648 1649 1650 |
if (optlen != sizeof(v)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1651 |
if (copy_from_sockptr(&v, optval, sizeof(v))) |
14fb64e1f [IPV6] MROUTE: Su... |
1652 1653 1654 1655 |
return -EFAULT; v = !!v; rtnl_lock(); ret = 0; |
6bd521433 ipv6: ip6mr: move... |
1656 1657 1658 |
if (v != mrt->mroute_do_pim) { mrt->mroute_do_pim = v; mrt->mroute_do_assert = v; |
14fb64e1f [IPV6] MROUTE: Su... |
1659 1660 1661 1662 1663 1664 |
} rtnl_unlock(); return ret; } #endif |
d1db275dd ipv6: ip6mr: supp... |
1665 1666 1667 1668 1669 1670 1671 |
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES case MRT6_TABLE: { u32 v; if (optlen != sizeof(u32)) return -EINVAL; |
b43c61531 net/ipv6: switch ... |
1672 |
if (copy_from_sockptr(&v, optval, sizeof(v))) |
d1db275dd ipv6: ip6mr: supp... |
1673 |
return -EFAULT; |
75356a814 ip6mr: limit IPv6... |
1674 1675 1676 |
/* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */ if (v != RT_TABLE_DEFAULT && v >= 100000000) return -EINVAL; |
b70432f73 mroute*: Make mr_... |
1677 |
if (sk == rcu_access_pointer(mrt->mroute_sk)) |
d1db275dd ipv6: ip6mr: supp... |
1678 1679 1680 1681 |
return -EBUSY; rtnl_lock(); ret = 0; |
e783bb00a ipmr: fix error p... |
1682 1683 1684 |
mrt = ip6mr_new_table(net, v); if (IS_ERR(mrt)) ret = PTR_ERR(mrt); |
848235edb ip6mr: only set i... |
1685 1686 |
else raw6_sk(sk)->ip6mr_table = v; |
d1db275dd ipv6: ip6mr: supp... |
1687 1688 1689 1690 |
rtnl_unlock(); return ret; } #endif |
14fb64e1f [IPV6] MROUTE: Su... |
1691 |
/* |
7d120c55d ipv6 mroute: Use ... |
1692 |
* Spurious command, or MRT6_VERSION which you cannot |
7bc570c8b [IPV6] MROUTE: Su... |
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 |
* set. */ default: return -ENOPROTOOPT; } } /* * Getsock opt support for the multicast routing system. */ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen) { int olr; int val; |
8229efdae netns: ip6mr: ena... |
1709 |
struct net *net = sock_net(sk); |
b70432f73 mroute*: Make mr_... |
1710 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
1711 |
|
99253eb75 ipv6: check sk sk... |
1712 1713 1714 |
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_ICMPV6) return -EOPNOTSUPP; |
d1db275dd ipv6: ip6mr: supp... |
1715 |
mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
1716 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
1717 |
return -ENOENT; |
7bc570c8b [IPV6] MROUTE: Su... |
1718 1719 1720 1721 1722 |
switch (optname) { case MRT6_VERSION: val = 0x0305; break; |
14fb64e1f [IPV6] MROUTE: Su... |
1723 1724 |
#ifdef CONFIG_IPV6_PIMSM_V2 case MRT6_PIM: |
6bd521433 ipv6: ip6mr: move... |
1725 |
val = mrt->mroute_do_pim; |
14fb64e1f [IPV6] MROUTE: Su... |
1726 1727 1728 |
break; #endif case MRT6_ASSERT: |
6bd521433 ipv6: ip6mr: move... |
1729 |
val = mrt->mroute_do_assert; |
14fb64e1f [IPV6] MROUTE: Su... |
1730 |
break; |
7bc570c8b [IPV6] MROUTE: Su... |
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 |
default: return -ENOPROTOOPT; } if (get_user(olr, optlen)) return -EFAULT; olr = min_t(int, olr, sizeof(int)); if (olr < 0) return -EINVAL; if (put_user(olr, optlen)) return -EFAULT; if (copy_to_user(optval, &val, olr)) return -EFAULT; return 0; } /* * The IP multicast ioctl support routines. */ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) { struct sioc_sg_req6 sr; struct sioc_mif_req6 vr; |
6853f21f7 ipmr,ipmr6: Defin... |
1757 |
struct vif_device *vif; |
7bc570c8b [IPV6] MROUTE: Su... |
1758 |
struct mfc6_cache *c; |
8229efdae netns: ip6mr: ena... |
1759 |
struct net *net = sock_net(sk); |
b70432f73 mroute*: Make mr_... |
1760 |
struct mr_table *mrt; |
d1db275dd ipv6: ip6mr: supp... |
1761 1762 |
mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
1763 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
1764 |
return -ENOENT; |
7bc570c8b [IPV6] MROUTE: Su... |
1765 1766 1767 1768 1769 |
switch (cmd) { case SIOCGETMIFCNT_IN6: if (copy_from_user(&vr, arg, sizeof(vr))) return -EFAULT; |
6bd521433 ipv6: ip6mr: move... |
1770 |
if (vr.mifi >= mrt->maxvif) |
7bc570c8b [IPV6] MROUTE: Su... |
1771 |
return -EINVAL; |
69d2c8676 ip6mr: Fix potent... |
1772 |
vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif); |
7bc570c8b [IPV6] MROUTE: Su... |
1773 |
read_lock(&mrt_lock); |
b70432f73 mroute*: Make mr_... |
1774 1775 |
vif = &mrt->vif_table[vr.mifi]; if (VIF_EXISTS(mrt, vr.mifi)) { |
7bc570c8b [IPV6] MROUTE: Su... |
1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 |
vr.icount = vif->pkt_in; vr.ocount = vif->pkt_out; vr.ibytes = vif->bytes_in; vr.obytes = vif->bytes_out; read_unlock(&mrt_lock); if (copy_to_user(arg, &vr, sizeof(vr))) return -EFAULT; return 0; } read_unlock(&mrt_lock); return -EADDRNOTAVAIL; case SIOCGETSGCNT_IN6: if (copy_from_user(&sr, arg, sizeof(sr))) return -EFAULT; |
87c418bf1 ip6mr: Align hash... |
1791 |
rcu_read_lock(); |
6bd521433 ipv6: ip6mr: move... |
1792 |
c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); |
7bc570c8b [IPV6] MROUTE: Su... |
1793 |
if (c) { |
494fff563 ipmr, ip6mr: Make... |
1794 1795 1796 |
sr.pktcnt = c->_c.mfc_un.res.pkt; sr.bytecnt = c->_c.mfc_un.res.bytes; sr.wrong_if = c->_c.mfc_un.res.wrong_if; |
87c418bf1 ip6mr: Align hash... |
1797 |
rcu_read_unlock(); |
7bc570c8b [IPV6] MROUTE: Su... |
1798 1799 1800 1801 1802 |
if (copy_to_user(arg, &sr, sizeof(sr))) return -EFAULT; return 0; } |
87c418bf1 ip6mr: Align hash... |
1803 |
rcu_read_unlock(); |
7bc570c8b [IPV6] MROUTE: Su... |
1804 1805 1806 1807 1808 |
return -EADDRNOTAVAIL; default: return -ENOIOCTLCMD; } } |
e2d57766e net: Provide comp... |
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 |
#ifdef CONFIG_COMPAT struct compat_sioc_sg_req6 { struct sockaddr_in6 src; struct sockaddr_in6 grp; compat_ulong_t pktcnt; compat_ulong_t bytecnt; compat_ulong_t wrong_if; }; struct compat_sioc_mif_req6 { mifi_t mifi; compat_ulong_t icount; compat_ulong_t ocount; compat_ulong_t ibytes; compat_ulong_t obytes; }; int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) { struct compat_sioc_sg_req6 sr; struct compat_sioc_mif_req6 vr; |
6853f21f7 ipmr,ipmr6: Defin... |
1830 |
struct vif_device *vif; |
e2d57766e net: Provide comp... |
1831 1832 |
struct mfc6_cache *c; struct net *net = sock_net(sk); |
b70432f73 mroute*: Make mr_... |
1833 |
struct mr_table *mrt; |
e2d57766e net: Provide comp... |
1834 1835 |
mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
1836 |
if (!mrt) |
e2d57766e net: Provide comp... |
1837 1838 1839 1840 1841 1842 1843 1844 |
return -ENOENT; switch (cmd) { case SIOCGETMIFCNT_IN6: if (copy_from_user(&vr, arg, sizeof(vr))) return -EFAULT; if (vr.mifi >= mrt->maxvif) return -EINVAL; |
69d2c8676 ip6mr: Fix potent... |
1845 |
vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif); |
e2d57766e net: Provide comp... |
1846 |
read_lock(&mrt_lock); |
b70432f73 mroute*: Make mr_... |
1847 1848 |
vif = &mrt->vif_table[vr.mifi]; if (VIF_EXISTS(mrt, vr.mifi)) { |
e2d57766e net: Provide comp... |
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 |
vr.icount = vif->pkt_in; vr.ocount = vif->pkt_out; vr.ibytes = vif->bytes_in; vr.obytes = vif->bytes_out; read_unlock(&mrt_lock); if (copy_to_user(arg, &vr, sizeof(vr))) return -EFAULT; return 0; } read_unlock(&mrt_lock); return -EADDRNOTAVAIL; case SIOCGETSGCNT_IN6: if (copy_from_user(&sr, arg, sizeof(sr))) return -EFAULT; |
87c418bf1 ip6mr: Align hash... |
1864 |
rcu_read_lock(); |
e2d57766e net: Provide comp... |
1865 1866 |
c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr); if (c) { |
494fff563 ipmr, ip6mr: Make... |
1867 1868 1869 |
sr.pktcnt = c->_c.mfc_un.res.pkt; sr.bytecnt = c->_c.mfc_un.res.bytes; sr.wrong_if = c->_c.mfc_un.res.wrong_if; |
87c418bf1 ip6mr: Align hash... |
1870 |
rcu_read_unlock(); |
e2d57766e net: Provide comp... |
1871 1872 1873 1874 1875 |
if (copy_to_user(arg, &sr, sizeof(sr))) return -EFAULT; return 0; } |
87c418bf1 ip6mr: Align hash... |
1876 |
rcu_read_unlock(); |
e2d57766e net: Provide comp... |
1877 1878 1879 1880 1881 1882 |
return -EADDRNOTAVAIL; default: return -ENOIOCTLCMD; } } #endif |
7bc570c8b [IPV6] MROUTE: Su... |
1883 |
|
0c4b51f00 netfilter: Pass n... |
1884 |
static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct sk_buff *skb) |
7bc570c8b [IPV6] MROUTE: Su... |
1885 |
{ |
87c11f1dd ip6mr: Do not cal... |
1886 1887 1888 1889 |
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTFORWDATAGRAMS); IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTOCTETS, skb->len); |
13206b6bf net: Pass net int... |
1890 |
return dst_output(net, sk, skb); |
7bc570c8b [IPV6] MROUTE: Su... |
1891 1892 1893 1894 1895 |
} /* * Processing handlers for ip6mr_forward */ |
b70432f73 mroute*: Make mr_... |
1896 |
static int ip6mr_forward2(struct net *net, struct mr_table *mrt, |
f5c6dfdef ip6mr: Drop mfc6_... |
1897 |
struct sk_buff *skb, int vifi) |
7bc570c8b [IPV6] MROUTE: Su... |
1898 1899 |
{ struct ipv6hdr *ipv6h; |
b70432f73 mroute*: Make mr_... |
1900 |
struct vif_device *vif = &mrt->vif_table[vifi]; |
7bc570c8b [IPV6] MROUTE: Su... |
1901 1902 |
struct net_device *dev; struct dst_entry *dst; |
4c9483b2f ipv6: Convert to ... |
1903 |
struct flowi6 fl6; |
7bc570c8b [IPV6] MROUTE: Su... |
1904 |
|
63159f29b ipv6: coding styl... |
1905 |
if (!vif->dev) |
7bc570c8b [IPV6] MROUTE: Su... |
1906 |
goto out_free; |
14fb64e1f [IPV6] MROUTE: Su... |
1907 1908 1909 1910 |
#ifdef CONFIG_IPV6_PIMSM_V2 if (vif->flags & MIFF_REGISTER) { vif->pkt_out++; vif->bytes_out += skb->len; |
dc58c78c0 ip6mr: Use on-dev... |
1911 1912 |
vif->dev->stats.tx_bytes += skb->len; vif->dev->stats.tx_packets++; |
6bd521433 ipv6: ip6mr: move... |
1913 |
ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT); |
8da73b73e ip6mr: use goto t... |
1914 |
goto out_free; |
14fb64e1f [IPV6] MROUTE: Su... |
1915 1916 |
} #endif |
7bc570c8b [IPV6] MROUTE: Su... |
1917 |
ipv6h = ipv6_hdr(skb); |
4c9483b2f ipv6: Convert to ... |
1918 1919 1920 |
fl6 = (struct flowi6) { .flowi6_oif = vif->link, .daddr = ipv6h->daddr, |
7bc570c8b [IPV6] MROUTE: Su... |
1921 |
}; |
4c9483b2f ipv6: Convert to ... |
1922 |
dst = ip6_route_output(net, NULL, &fl6); |
5095d64db ipv6: ip6_route_o... |
1923 1924 |
if (dst->error) { dst_release(dst); |
7bc570c8b [IPV6] MROUTE: Su... |
1925 |
goto out_free; |
5095d64db ipv6: ip6_route_o... |
1926 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
1927 |
|
adf30907d net: skb->dst acc... |
1928 1929 |
skb_dst_drop(skb); skb_dst_set(skb, dst); |
7bc570c8b [IPV6] MROUTE: Su... |
1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 |
/* * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally * not only before forwarding, but after forwarding on all output * interfaces. It is clear, if mrouter runs a multicasting * program, it should receive packets not depending to what interface * program is joined. * If we will not make it, the program will have to join on all * interfaces. On the other hand, multihoming host (or router, but * not mrouter) cannot join to more than one interface - it will * result in receiving multiple packets. */ dev = vif->dev; skb->dev = dev; vif->pkt_out++; vif->bytes_out += skb->len; /* We are about to write */ /* XXX: extension headers? */ if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev))) goto out_free; ipv6h = ipv6_hdr(skb); ipv6h->hop_limit--; IP6CB(skb)->flags |= IP6SKB_FORWARDED; |
29a26a568 netfilter: Pass s... |
1956 1957 |
return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, net, NULL, skb, skb->dev, dev, |
7bc570c8b [IPV6] MROUTE: Su... |
1958 1959 1960 1961 1962 1963 |
ip6mr_forward2_finish); out_free: kfree_skb(skb); return 0; } |
b70432f73 mroute*: Make mr_... |
1964 |
static int ip6mr_find_vif(struct mr_table *mrt, struct net_device *dev) |
7bc570c8b [IPV6] MROUTE: Su... |
1965 1966 |
{ int ct; |
6bd521433 ipv6: ip6mr: move... |
1967 1968 |
for (ct = mrt->maxvif - 1; ct >= 0; ct--) { |
b70432f73 mroute*: Make mr_... |
1969 |
if (mrt->vif_table[ct].dev == dev) |
7bc570c8b [IPV6] MROUTE: Su... |
1970 1971 1972 1973 |
break; } return ct; } |
b70432f73 mroute*: Make mr_... |
1974 |
static void ip6_mr_forward(struct net *net, struct mr_table *mrt, |
e4a38c0c4 ipv6: add vrf tab... |
1975 1976 |
struct net_device *dev, struct sk_buff *skb, struct mfc6_cache *c) |
7bc570c8b [IPV6] MROUTE: Su... |
1977 1978 1979 |
{ int psend = -1; int vif, ct; |
e4a38c0c4 ipv6: add vrf tab... |
1980 |
int true_vifi = ip6mr_find_vif(mrt, dev); |
7bc570c8b [IPV6] MROUTE: Su... |
1981 |
|
494fff563 ipmr, ip6mr: Make... |
1982 1983 1984 1985 |
vif = c->_c.mfc_parent; c->_c.mfc_un.res.pkt++; c->_c.mfc_un.res.bytes += skb->len; c->_c.mfc_un.res.lastuse = jiffies; |
7bc570c8b [IPV6] MROUTE: Su... |
1986 |
|
494fff563 ipmr, ip6mr: Make... |
1987 |
if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) { |
660b26dc1 mcast: add multic... |
1988 |
struct mfc6_cache *cache_proxy; |
40dc2ca3c ipv6: spelling s/... |
1989 |
/* For an (*,G) entry, we only check that the incoming |
660b26dc1 mcast: add multic... |
1990 1991 |
* interface is part of the static tree. */ |
87c418bf1 ip6mr: Align hash... |
1992 |
rcu_read_lock(); |
845c9a7ae ipmr, ip6mr: Unit... |
1993 |
cache_proxy = mr_mfc_find_any_parent(mrt, vif); |
660b26dc1 mcast: add multic... |
1994 |
if (cache_proxy && |
494fff563 ipmr, ip6mr: Make... |
1995 |
cache_proxy->_c.mfc_un.res.ttls[true_vifi] < 255) { |
87c418bf1 ip6mr: Align hash... |
1996 |
rcu_read_unlock(); |
660b26dc1 mcast: add multic... |
1997 |
goto forward; |
87c418bf1 ip6mr: Align hash... |
1998 1999 |
} rcu_read_unlock(); |
660b26dc1 mcast: add multic... |
2000 |
} |
14fb64e1f [IPV6] MROUTE: Su... |
2001 2002 2003 |
/* * Wrong interface: drop packet and (maybe) send PIM assert. */ |
e4a38c0c4 ipv6: add vrf tab... |
2004 |
if (mrt->vif_table[vif].dev != dev) { |
494fff563 ipmr, ip6mr: Make... |
2005 |
c->_c.mfc_un.res.wrong_if++; |
14fb64e1f [IPV6] MROUTE: Su... |
2006 |
|
6bd521433 ipv6: ip6mr: move... |
2007 |
if (true_vifi >= 0 && mrt->mroute_do_assert && |
14fb64e1f [IPV6] MROUTE: Su... |
2008 2009 2010 2011 2012 |
/* pimsm uses asserts, when switching from RPT to SPT, so that we cannot check that packet arrived on an oif. It is bad, but otherwise we would need to move pretty large chunk of pimd to kernel. Ough... --ANK */ |
6bd521433 ipv6: ip6mr: move... |
2013 |
(mrt->mroute_do_pim || |
494fff563 ipmr, ip6mr: Make... |
2014 |
c->_c.mfc_un.res.ttls[true_vifi] < 255) && |
14fb64e1f [IPV6] MROUTE: Su... |
2015 |
time_after(jiffies, |
494fff563 ipmr, ip6mr: Make... |
2016 2017 2018 |
c->_c.mfc_un.res.last_assert + MFC_ASSERT_THRESH)) { c->_c.mfc_un.res.last_assert = jiffies; |
6bd521433 ipv6: ip6mr: move... |
2019 |
ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF); |
14fb64e1f [IPV6] MROUTE: Su... |
2020 2021 2022 |
} goto dont_forward; } |
660b26dc1 mcast: add multic... |
2023 |
forward: |
b70432f73 mroute*: Make mr_... |
2024 2025 |
mrt->vif_table[vif].pkt_in++; mrt->vif_table[vif].bytes_in += skb->len; |
7bc570c8b [IPV6] MROUTE: Su... |
2026 2027 2028 2029 |
/* * Forward the frame */ |
494fff563 ipmr, ip6mr: Make... |
2030 2031 |
if (ipv6_addr_any(&c->mf6c_origin) && ipv6_addr_any(&c->mf6c_mcastgrp)) { |
660b26dc1 mcast: add multic... |
2032 |
if (true_vifi >= 0 && |
494fff563 ipmr, ip6mr: Make... |
2033 |
true_vifi != c->_c.mfc_parent && |
660b26dc1 mcast: add multic... |
2034 |
ipv6_hdr(skb)->hop_limit > |
494fff563 ipmr, ip6mr: Make... |
2035 |
c->_c.mfc_un.res.ttls[c->_c.mfc_parent]) { |
660b26dc1 mcast: add multic... |
2036 2037 2038 2039 |
/* It's an (*,*) entry and the packet is not coming from * the upstream: forward the packet to the upstream * only. */ |
494fff563 ipmr, ip6mr: Make... |
2040 |
psend = c->_c.mfc_parent; |
660b26dc1 mcast: add multic... |
2041 2042 2043 2044 |
goto last_forward; } goto dont_forward; } |
494fff563 ipmr, ip6mr: Make... |
2045 2046 |
for (ct = c->_c.mfc_un.res.maxvif - 1; ct >= c->_c.mfc_un.res.minvif; ct--) { |
660b26dc1 mcast: add multic... |
2047 |
/* For (*,G) entry, don't forward to the incoming interface */ |
494fff563 ipmr, ip6mr: Make... |
2048 2049 |
if ((!ipv6_addr_any(&c->mf6c_origin) || ct != true_vifi) && ipv6_hdr(skb)->hop_limit > c->_c.mfc_un.res.ttls[ct]) { |
7bc570c8b [IPV6] MROUTE: Su... |
2050 2051 2052 |
if (psend != -1) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) |
f5c6dfdef ip6mr: Drop mfc6_... |
2053 |
ip6mr_forward2(net, mrt, skb2, psend); |
7bc570c8b [IPV6] MROUTE: Su... |
2054 2055 2056 2057 |
} psend = ct; } } |
660b26dc1 mcast: add multic... |
2058 |
last_forward: |
7bc570c8b [IPV6] MROUTE: Su... |
2059 |
if (psend != -1) { |
f5c6dfdef ip6mr: Drop mfc6_... |
2060 |
ip6mr_forward2(net, mrt, skb, psend); |
2b52c3ada ip6mr: change the... |
2061 |
return; |
7bc570c8b [IPV6] MROUTE: Su... |
2062 |
} |
14fb64e1f [IPV6] MROUTE: Su... |
2063 |
dont_forward: |
7bc570c8b [IPV6] MROUTE: Su... |
2064 |
kfree_skb(skb); |
7bc570c8b [IPV6] MROUTE: Su... |
2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 |
} /* * Multicast packets for forwarding arrive here */ int ip6_mr_input(struct sk_buff *skb) { struct mfc6_cache *cache; |
8229efdae netns: ip6mr: ena... |
2075 |
struct net *net = dev_net(skb->dev); |
b70432f73 mroute*: Make mr_... |
2076 |
struct mr_table *mrt; |
4c9483b2f ipv6: Convert to ... |
2077 2078 2079 |
struct flowi6 fl6 = { .flowi6_iif = skb->dev->ifindex, .flowi6_mark = skb->mark, |
d1db275dd ipv6: ip6mr: supp... |
2080 2081 |
}; int err; |
e4a38c0c4 ipv6: add vrf tab... |
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 |
struct net_device *dev; /* skb->dev passed in is the master dev for vrfs. * Get the proper interface that does have a vif associated with it. */ dev = skb->dev; if (netif_is_l3_master(skb->dev)) { dev = dev_get_by_index_rcu(net, IPCB(skb)->iif); if (!dev) { kfree_skb(skb); return -ENODEV; } } |
d1db275dd ipv6: ip6mr: supp... |
2095 |
|
4c9483b2f ipv6: Convert to ... |
2096 |
err = ip6mr_fib_lookup(net, &fl6, &mrt); |
2015de5fe ipv6-multicast: F... |
2097 2098 |
if (err < 0) { kfree_skb(skb); |
d1db275dd ipv6: ip6mr: supp... |
2099 |
return err; |
2015de5fe ipv6-multicast: F... |
2100 |
} |
7bc570c8b [IPV6] MROUTE: Su... |
2101 2102 |
read_lock(&mrt_lock); |
6bd521433 ipv6: ip6mr: move... |
2103 |
cache = ip6mr_cache_find(mrt, |
8229efdae netns: ip6mr: ena... |
2104 |
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); |
63159f29b ipv6: coding styl... |
2105 |
if (!cache) { |
e4a38c0c4 ipv6: add vrf tab... |
2106 |
int vif = ip6mr_find_vif(mrt, dev); |
660b26dc1 mcast: add multic... |
2107 2108 2109 2110 2111 2112 |
if (vif >= 0) cache = ip6mr_cache_find_any(mrt, &ipv6_hdr(skb)->daddr, vif); } |
7bc570c8b [IPV6] MROUTE: Su... |
2113 2114 2115 2116 |
/* * No usable cache entry */ |
63159f29b ipv6: coding styl... |
2117 |
if (!cache) { |
7bc570c8b [IPV6] MROUTE: Su... |
2118 |
int vif; |
e4a38c0c4 ipv6: add vrf tab... |
2119 |
vif = ip6mr_find_vif(mrt, dev); |
7bc570c8b [IPV6] MROUTE: Su... |
2120 |
if (vif >= 0) { |
e4a38c0c4 ipv6: add vrf tab... |
2121 |
int err = ip6mr_cache_unresolved(mrt, vif, skb, dev); |
7bc570c8b [IPV6] MROUTE: Su... |
2122 2123 2124 2125 2126 2127 2128 2129 |
read_unlock(&mrt_lock); return err; } read_unlock(&mrt_lock); kfree_skb(skb); return -ENODEV; } |
e4a38c0c4 ipv6: add vrf tab... |
2130 |
ip6_mr_forward(net, mrt, dev, skb, cache); |
7bc570c8b [IPV6] MROUTE: Su... |
2131 2132 2133 2134 2135 |
read_unlock(&mrt_lock); return 0; } |
2cf750704 ipmr, ip6mr: fix ... |
2136 |
int ip6mr_get_route(struct net *net, struct sk_buff *skb, struct rtmsg *rtm, |
fd61c6ba3 net: ipv6: remove... |
2137 |
u32 portid) |
7bc570c8b [IPV6] MROUTE: Su... |
2138 2139 |
{ int err; |
b70432f73 mroute*: Make mr_... |
2140 |
struct mr_table *mrt; |
7bc570c8b [IPV6] MROUTE: Su... |
2141 |
struct mfc6_cache *cache; |
adf30907d net: skb->dst acc... |
2142 |
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); |
7bc570c8b [IPV6] MROUTE: Su... |
2143 |
|
d1db275dd ipv6: ip6mr: supp... |
2144 |
mrt = ip6mr_get_table(net, RT6_TABLE_DFLT); |
63159f29b ipv6: coding styl... |
2145 |
if (!mrt) |
d1db275dd ipv6: ip6mr: supp... |
2146 |
return -ENOENT; |
7bc570c8b [IPV6] MROUTE: Su... |
2147 |
read_lock(&mrt_lock); |
6bd521433 ipv6: ip6mr: move... |
2148 |
cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); |
660b26dc1 mcast: add multic... |
2149 2150 2151 2152 2153 2154 2155 |
if (!cache && skb->dev) { int vif = ip6mr_find_vif(mrt, skb->dev); if (vif >= 0) cache = ip6mr_cache_find_any(mrt, &rt->rt6i_dst.addr, vif); } |
7bc570c8b [IPV6] MROUTE: Su... |
2156 2157 2158 2159 2160 2161 |
if (!cache) { struct sk_buff *skb2; struct ipv6hdr *iph; struct net_device *dev; int vif; |
7bc570c8b [IPV6] MROUTE: Su... |
2162 |
dev = skb->dev; |
63159f29b ipv6: coding styl... |
2163 |
if (!dev || (vif = ip6mr_find_vif(mrt, dev)) < 0) { |
7bc570c8b [IPV6] MROUTE: Su... |
2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 |
read_unlock(&mrt_lock); return -ENODEV; } /* really correct? */ skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); if (!skb2) { read_unlock(&mrt_lock); return -ENOMEM; } |
2cf750704 ipmr, ip6mr: fix ... |
2174 |
NETLINK_CB(skb2).portid = portid; |
7bc570c8b [IPV6] MROUTE: Su... |
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 |
skb_reset_transport_header(skb2); skb_put(skb2, sizeof(struct ipv6hdr)); skb_reset_network_header(skb2); iph = ipv6_hdr(skb2); iph->version = 0; iph->priority = 0; iph->flow_lbl[0] = 0; iph->flow_lbl[1] = 0; iph->flow_lbl[2] = 0; iph->payload_len = 0; iph->nexthdr = IPPROTO_NONE; iph->hop_limit = 0; |
4e3fd7a06 net: remove ipv6_... |
2189 2190 |
iph->saddr = rt->rt6i_src.addr; iph->daddr = rt->rt6i_dst.addr; |
7bc570c8b [IPV6] MROUTE: Su... |
2191 |
|
e4a38c0c4 ipv6: add vrf tab... |
2192 |
err = ip6mr_cache_unresolved(mrt, vif, skb2, dev); |
7bc570c8b [IPV6] MROUTE: Su... |
2193 2194 2195 2196 |
read_unlock(&mrt_lock); return err; } |
7b0db8573 ipmr, ip6mr: Unit... |
2197 |
err = mr_fill_mroute(mrt, skb, &cache->_c, rtm); |
7bc570c8b [IPV6] MROUTE: Su... |
2198 2199 2200 |
read_unlock(&mrt_lock); return err; } |
b70432f73 mroute*: Make mr_... |
2201 |
static int ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, |
f518338b1 ip6mr: fix mfc no... |
2202 2203 |
u32 portid, u32 seq, struct mfc6_cache *c, int cmd, int flags) |
5b285cac3 ipv6: ip6mr: add ... |
2204 2205 2206 |
{ struct nlmsghdr *nlh; struct rtmsg *rtm; |
1eb99af52 ipmr/ip6mr: allow... |
2207 |
int err; |
5b285cac3 ipv6: ip6mr: add ... |
2208 |
|
f518338b1 ip6mr: fix mfc no... |
2209 |
nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags); |
63159f29b ipv6: coding styl... |
2210 |
if (!nlh) |
5b285cac3 ipv6: ip6mr: add ... |
2211 2212 2213 |
return -EMSGSIZE; rtm = nlmsg_data(nlh); |
193c1e478 ip6mr: fix rtm_fa... |
2214 |
rtm->rtm_family = RTNL_FAMILY_IP6MR; |
5b285cac3 ipv6: ip6mr: add ... |
2215 2216 2217 2218 |
rtm->rtm_dst_len = 128; rtm->rtm_src_len = 128; rtm->rtm_tos = 0; rtm->rtm_table = mrt->id; |
c78679e8f ipv6: Stop using ... |
2219 2220 |
if (nla_put_u32(skb, RTA_TABLE, mrt->id)) goto nla_put_failure; |
1eb99af52 ipmr/ip6mr: allow... |
2221 |
rtm->rtm_type = RTN_MULTICAST; |
5b285cac3 ipv6: ip6mr: add ... |
2222 |
rtm->rtm_scope = RT_SCOPE_UNIVERSE; |
494fff563 ipmr, ip6mr: Make... |
2223 |
if (c->_c.mfc_flags & MFC_STATIC) |
9a68ac72a ipmr/ip6mr: repor... |
2224 2225 2226 |
rtm->rtm_protocol = RTPROT_STATIC; else rtm->rtm_protocol = RTPROT_MROUTED; |
5b285cac3 ipv6: ip6mr: add ... |
2227 |
rtm->rtm_flags = 0; |
930345ea6 netlink: implemen... |
2228 2229 |
if (nla_put_in6_addr(skb, RTA_SRC, &c->mf6c_origin) || nla_put_in6_addr(skb, RTA_DST, &c->mf6c_mcastgrp)) |
c78679e8f ipv6: Stop using ... |
2230 |
goto nla_put_failure; |
7b0db8573 ipmr, ip6mr: Unit... |
2231 |
err = mr_fill_mroute(mrt, skb, &c->_c, rtm); |
1eb99af52 ipmr/ip6mr: allow... |
2232 2233 |
/* do not break the dump if cache is unresolved */ if (err < 0 && err != -ENOENT) |
5b285cac3 ipv6: ip6mr: add ... |
2234 |
goto nla_put_failure; |
053c095a8 netlink: make nlm... |
2235 2236 |
nlmsg_end(skb, nlh); return 0; |
5b285cac3 ipv6: ip6mr: add ... |
2237 2238 2239 2240 2241 |
nla_put_failure: nlmsg_cancel(skb, nlh); return -EMSGSIZE; } |
7b0db8573 ipmr, ip6mr: Unit... |
2242 2243 2244 2245 2246 2247 2248 |
static int _ip6mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb, u32 portid, u32 seq, struct mr_mfc *c, int cmd, int flags) { return ip6mr_fill_mroute(mrt, skb, portid, seq, (struct mfc6_cache *)c, cmd, flags); } |
812e44dd1 ip6mr: advertise ... |
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 |
static int mr6_msgsize(bool unresolved, int maxvif) { size_t len = NLMSG_ALIGN(sizeof(struct rtmsg)) + nla_total_size(4) /* RTA_TABLE */ + nla_total_size(sizeof(struct in6_addr)) /* RTA_SRC */ + nla_total_size(sizeof(struct in6_addr)) /* RTA_DST */ ; if (!unresolved) len = len + nla_total_size(4) /* RTA_IIF */ + nla_total_size(0) /* RTA_MULTIPATH */ + maxvif * NLA_ALIGN(sizeof(struct rtnexthop)) /* RTA_MFC_STATS */ |
3d6b66c1d ip6mr: align RTA_... |
2264 |
+ nla_total_size_64bit(sizeof(struct rta_mfc_stats)) |
812e44dd1 ip6mr: advertise ... |
2265 2266 2267 2268 |
; return len; } |
b70432f73 mroute*: Make mr_... |
2269 |
static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc, |
812e44dd1 ip6mr: advertise ... |
2270 2271 2272 2273 2274 |
int cmd) { struct net *net = read_pnet(&mrt->net); struct sk_buff *skb; int err = -ENOBUFS; |
494fff563 ipmr, ip6mr: Make... |
2275 |
skb = nlmsg_new(mr6_msgsize(mfc->_c.mfc_parent >= MAXMIFS, mrt->maxvif), |
812e44dd1 ip6mr: advertise ... |
2276 |
GFP_ATOMIC); |
63159f29b ipv6: coding styl... |
2277 |
if (!skb) |
812e44dd1 ip6mr: advertise ... |
2278 |
goto errout; |
f518338b1 ip6mr: fix mfc no... |
2279 |
err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0); |
812e44dd1 ip6mr: advertise ... |
2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 |
if (err < 0) goto errout; rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE, NULL, GFP_ATOMIC); return; errout: kfree_skb(skb); if (err < 0) rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE, err); } |
dd12d15c9 ip6mr: add netlin... |
2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 |
static size_t mrt6msg_netlink_msgsize(size_t payloadlen) { size_t len = NLMSG_ALIGN(sizeof(struct rtgenmsg)) + nla_total_size(1) /* IP6MRA_CREPORT_MSGTYPE */ + nla_total_size(4) /* IP6MRA_CREPORT_MIF_ID */ /* IP6MRA_CREPORT_SRC_ADDR */ + nla_total_size(sizeof(struct in6_addr)) /* IP6MRA_CREPORT_DST_ADDR */ + nla_total_size(sizeof(struct in6_addr)) /* IP6MRA_CREPORT_PKT */ + nla_total_size(payloadlen) ; return len; } |
b70432f73 mroute*: Make mr_... |
2307 |
static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt) |
dd12d15c9 ip6mr: add netlin... |
2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 |
{ struct net *net = read_pnet(&mrt->net); struct nlmsghdr *nlh; struct rtgenmsg *rtgenm; struct mrt6msg *msg; struct sk_buff *skb; struct nlattr *nla; int payloadlen; payloadlen = pkt->len - sizeof(struct mrt6msg); msg = (struct mrt6msg *)skb_transport_header(pkt); skb = nlmsg_new(mrt6msg_netlink_msgsize(payloadlen), GFP_ATOMIC); if (!skb) goto errout; nlh = nlmsg_put(skb, 0, 0, RTM_NEWCACHEREPORT, sizeof(struct rtgenmsg), 0); if (!nlh) goto errout; rtgenm = nlmsg_data(nlh); rtgenm->rtgen_family = RTNL_FAMILY_IP6MR; if (nla_put_u8(skb, IP6MRA_CREPORT_MSGTYPE, msg->im6_msgtype) || nla_put_u32(skb, IP6MRA_CREPORT_MIF_ID, msg->im6_mif) || nla_put_in6_addr(skb, IP6MRA_CREPORT_SRC_ADDR, &msg->im6_src) || nla_put_in6_addr(skb, IP6MRA_CREPORT_DST_ADDR, &msg->im6_dst)) goto nla_put_failure; nla = nla_reserve(skb, IP6MRA_CREPORT_PKT, payloadlen); if (!nla || skb_copy_bits(pkt, sizeof(struct mrt6msg), nla_data(nla), payloadlen)) goto nla_put_failure; nlmsg_end(skb, nlh); rtnl_notify(skb, net, 0, RTNLGRP_IPV6_MROUTE_R, NULL, GFP_ATOMIC); return; nla_put_failure: nlmsg_cancel(skb, nlh); errout: kfree_skb(skb); rtnl_set_sk_err(net, RTNLGRP_IPV6_MROUTE_R, -ENOBUFS); } |
5b285cac3 ipv6: ip6mr: add ... |
2354 2355 |
static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) { |
e8ba330ac rtnetlink: Update... |
2356 |
const struct nlmsghdr *nlh = cb->nlh; |
4724676d5 net: Add struct f... |
2357 |
struct fib_dump_filter filter = {}; |
cb167893f net: Plumb suppor... |
2358 |
int err; |
e8ba330ac rtnetlink: Update... |
2359 2360 |
if (cb->strict_check) { |
4724676d5 net: Add struct f... |
2361 |
err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh, |
effe67926 net: Enable kerne... |
2362 |
&filter, cb); |
e8ba330ac rtnetlink: Update... |
2363 2364 2365 |
if (err < 0) return err; } |
cb167893f net: Plumb suppor... |
2366 2367 2368 2369 2370 |
if (filter.table_id) { struct mr_table *mrt; mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id); if (!mrt) { |
41b4bd986 net: don't return... |
2371 |
if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR) |
ae677bbb4 net: Don't return... |
2372 |
return skb->len; |
cb167893f net: Plumb suppor... |
2373 2374 2375 2376 2377 2378 2379 |
NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist"); return -ENOENT; } err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute, &mfc_unres_lock, &filter); return skb->len ? : err; } |
7b0db8573 ipmr, ip6mr: Unit... |
2380 |
return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter, |
cb167893f net: Plumb suppor... |
2381 |
_ip6mr_fill_mroute, &mfc_unres_lock, &filter); |
5b285cac3 ipv6: ip6mr: add ... |
2382 |
} |