aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig26
-rw-r--r--net/ipv6/addrconf.c346
-rw-r--r--net/ipv6/af_inet6.c120
-rw-r--r--net/ipv6/ah6.c5
-rw-r--r--net/ipv6/anycast.c7
-rw-r--r--net/ipv6/esp6.c5
-rw-r--r--net/ipv6/ip6_fib.c1
-rw-r--r--net/ipv6/ip6_flowlabel.c6
-rw-r--r--net/ipv6/ip6_output.c43
-rw-r--r--net/ipv6/ipcomp6.c22
-rw-r--r--net/ipv6/ipv6_sockglue.c163
-rw-r--r--net/ipv6/mcast.c17
-rw-r--r--net/ipv6/ndisc.c49
-rw-r--r--net/ipv6/netfilter/Kconfig10
-rw-r--r--net/ipv6/netfilter/Makefile1
-rw-r--r--net/ipv6/netfilter/ip6_queue.c11
-rw-r--r--net/ipv6/netfilter/ip6_tables.c87
-rw-r--r--net/ipv6/netfilter/ip6t_HL.c19
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c11
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c25
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c12
-rw-r--r--net/ipv6/netfilter/ip6t_dst.c13
-rw-r--r--net/ipv6/netfilter/ip6t_esp.c12
-rw-r--r--net/ipv6/netfilter/ip6t_eui64.c27
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c13
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c13
-rw-r--r--net/ipv6/netfilter/ip6t_hl.c22
-rw-r--r--net/ipv6/netfilter/ip6t_ipv6header.c8
-rw-r--r--net/ipv6/netfilter/ip6t_multiport.c11
-rw-r--r--net/ipv6/netfilter/ip6t_owner.c18
-rw-r--r--net/ipv6/netfilter/ip6t_policy.c176
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c12
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c39
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c8
-rw-r--r--net/ipv6/raw.c145
-rw-r--r--net/ipv6/reassembly.c35
-rw-r--r--net/ipv6/route.c680
-rw-r--r--net/ipv6/tcp_ipv6.c74
-rw-r--r--net/ipv6/udp.c84
-rw-r--r--net/ipv6/xfrm6_tunnel.c11
40 files changed, 1280 insertions, 1107 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ab7a9124f985..e6f83b6a2b76 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -6,8 +6,6 @@
6config IPV6 6config IPV6
7 tristate "The IPv6 protocol" 7 tristate "The IPv6 protocol"
8 default m 8 default m
9 select CRYPTO if IPV6_PRIVACY
10 select CRYPTO_MD5 if IPV6_PRIVACY
11 ---help--- 9 ---help---
12 This is complemental support for the IP version 6. 10 This is complemental support for the IP version 6.
13 You will still be able to do traditional IPv4 networking as well. 11 You will still be able to do traditional IPv4 networking as well.
@@ -22,7 +20,7 @@ config IPV6
22 module will be called ipv6. 20 module will be called ipv6.
23 21
24config IPV6_PRIVACY 22config IPV6_PRIVACY
25 bool "IPv6: Privacy Extensions (RFC 3041) support" 23 bool "IPv6: Privacy Extensions support"
26 depends on IPV6 24 depends on IPV6
27 ---help--- 25 ---help---
28 Privacy Extensions for Stateless Address Autoconfiguration in IPv6 26 Privacy Extensions for Stateless Address Autoconfiguration in IPv6
@@ -30,6 +28,9 @@ config IPV6_PRIVACY
30 pseudo-random global-scope unicast address(es) will assigned to 28 pseudo-random global-scope unicast address(es) will assigned to
31 your interface(s). 29 your interface(s).
32 30
31 We use our standard pseudo random algorithm to generate randomized
32 interface identifier, instead of one described in RFC 3041.
33
33 By default, kernel do not generate temporary addresses. 34 By default, kernel do not generate temporary addresses.
34 To use temporary addresses, do 35 To use temporary addresses, do
35 36
@@ -37,6 +38,25 @@ config IPV6_PRIVACY
37 38
38 See <file:Documentation/networking/ip-sysctl.txt> for details. 39 See <file:Documentation/networking/ip-sysctl.txt> for details.
39 40
41config IPV6_ROUTER_PREF
42 bool "IPv6: Router Preference (RFC 4191) support"
43 depends on IPV6
44 ---help---
45 Router Preference is an optional extension to the Router
46 Advertisement message to improve the ability of hosts
47 to pick more appropriate router, especially when the hosts
48 is placed in a multi-homed network.
49
50 If unsure, say N.
51
52config IPV6_ROUTE_INFO
53 bool "IPv6: Route Information (RFC 4191) support (EXPERIMENTAL)"
54 depends on IPV6_ROUTER_PREF && EXPERIMENTAL
55 ---help---
56 This is experimental support of Route Information.
57
58 If unsure, say N.
59
40config INET6_AH 60config INET6_AH
41 tristate "IPv6: AH transformation" 61 tristate "IPv6: AH transformation"
42 depends on IPV6 62 depends on IPV6
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 19727d941962..01c62a0d3742 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -78,8 +78,6 @@
78 78
79#ifdef CONFIG_IPV6_PRIVACY 79#ifdef CONFIG_IPV6_PRIVACY
80#include <linux/random.h> 80#include <linux/random.h>
81#include <linux/crypto.h>
82#include <linux/scatterlist.h>
83#endif 81#endif
84 82
85#include <asm/uaccess.h> 83#include <asm/uaccess.h>
@@ -110,8 +108,6 @@ static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad
110static void ipv6_regen_rndid(unsigned long data); 108static void ipv6_regen_rndid(unsigned long data);
111 109
112static int desync_factor = MAX_DESYNC_FACTOR * HZ; 110static int desync_factor = MAX_DESYNC_FACTOR * HZ;
113static struct crypto_tfm *md5_tfm;
114static DEFINE_SPINLOCK(md5_tfm_lock);
115#endif 111#endif
116 112
117static int ipv6_count_addresses(struct inet6_dev *idev); 113static int ipv6_count_addresses(struct inet6_dev *idev);
@@ -169,6 +165,15 @@ struct ipv6_devconf ipv6_devconf = {
169 .max_desync_factor = MAX_DESYNC_FACTOR, 165 .max_desync_factor = MAX_DESYNC_FACTOR,
170#endif 166#endif
171 .max_addresses = IPV6_MAX_ADDRESSES, 167 .max_addresses = IPV6_MAX_ADDRESSES,
168 .accept_ra_defrtr = 1,
169 .accept_ra_pinfo = 1,
170#ifdef CONFIG_IPV6_ROUTER_PREF
171 .accept_ra_rtr_pref = 1,
172 .rtr_probe_interval = 60 * HZ,
173#ifdef CONFIG_IPV6_ROUTE_INFO
174 .accept_ra_rt_info_max_plen = 0,
175#endif
176#endif
172}; 177};
173 178
174static struct ipv6_devconf ipv6_devconf_dflt = { 179static struct ipv6_devconf ipv6_devconf_dflt = {
@@ -190,6 +195,15 @@ static struct ipv6_devconf ipv6_devconf_dflt = {
190 .max_desync_factor = MAX_DESYNC_FACTOR, 195 .max_desync_factor = MAX_DESYNC_FACTOR,
191#endif 196#endif
192 .max_addresses = IPV6_MAX_ADDRESSES, 197 .max_addresses = IPV6_MAX_ADDRESSES,
198 .accept_ra_defrtr = 1,
199 .accept_ra_pinfo = 1,
200#ifdef CONFIG_IPV6_ROUTER_PREF
201 .accept_ra_rtr_pref = 1,
202 .rtr_probe_interval = 60 * HZ,
203#ifdef CONFIG_IPV6_ROUTE_INFO
204 .accept_ra_rt_info_max_plen = 0,
205#endif
206#endif
193}; 207};
194 208
195/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ 209/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -327,86 +341,83 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
327 if (dev->mtu < IPV6_MIN_MTU) 341 if (dev->mtu < IPV6_MIN_MTU)
328 return NULL; 342 return NULL;
329 343
330 ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL); 344 ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
331 345
332 if (ndev) { 346 if (ndev == NULL)
333 memset(ndev, 0, sizeof(struct inet6_dev)); 347 return NULL;
334 348
335 rwlock_init(&ndev->lock); 349 rwlock_init(&ndev->lock);
336 ndev->dev = dev; 350 ndev->dev = dev;
337 memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf)); 351 memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
338 ndev->cnf.mtu6 = dev->mtu; 352 ndev->cnf.mtu6 = dev->mtu;
339 ndev->cnf.sysctl = NULL; 353 ndev->cnf.sysctl = NULL;
340 ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); 354 ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
341 if (ndev->nd_parms == NULL) { 355 if (ndev->nd_parms == NULL) {
342 kfree(ndev); 356 kfree(ndev);
343 return NULL; 357 return NULL;
344 } 358 }
345 /* We refer to the device */ 359 /* We refer to the device */
346 dev_hold(dev); 360 dev_hold(dev);
347
348 if (snmp6_alloc_dev(ndev) < 0) {
349 ADBG((KERN_WARNING
350 "%s(): cannot allocate memory for statistics; dev=%s.\n",
351 __FUNCTION__, dev->name));
352 neigh_parms_release(&nd_tbl, ndev->nd_parms);
353 ndev->dead = 1;
354 in6_dev_finish_destroy(ndev);
355 return NULL;
356 }
357 361
358 if (snmp6_register_dev(ndev) < 0) { 362 if (snmp6_alloc_dev(ndev) < 0) {
359 ADBG((KERN_WARNING 363 ADBG((KERN_WARNING
360 "%s(): cannot create /proc/net/dev_snmp6/%s\n", 364 "%s(): cannot allocate memory for statistics; dev=%s.\n",
361 __FUNCTION__, dev->name)); 365 __FUNCTION__, dev->name));
362 neigh_parms_release(&nd_tbl, ndev->nd_parms); 366 neigh_parms_release(&nd_tbl, ndev->nd_parms);
363 ndev->dead = 1; 367 ndev->dead = 1;
364 in6_dev_finish_destroy(ndev); 368 in6_dev_finish_destroy(ndev);
365 return NULL; 369 return NULL;
366 } 370 }
367 371
368 /* One reference from device. We must do this before 372 if (snmp6_register_dev(ndev) < 0) {
369 * we invoke __ipv6_regen_rndid(). 373 ADBG((KERN_WARNING
370 */ 374 "%s(): cannot create /proc/net/dev_snmp6/%s\n",
371 in6_dev_hold(ndev); 375 __FUNCTION__, dev->name));
376 neigh_parms_release(&nd_tbl, ndev->nd_parms);
377 ndev->dead = 1;
378 in6_dev_finish_destroy(ndev);
379 return NULL;
380 }
381
382 /* One reference from device. We must do this before
383 * we invoke __ipv6_regen_rndid().
384 */
385 in6_dev_hold(ndev);
372 386
373#ifdef CONFIG_IPV6_PRIVACY 387#ifdef CONFIG_IPV6_PRIVACY
374 get_random_bytes(ndev->rndid, sizeof(ndev->rndid)); 388 init_timer(&ndev->regen_timer);
375 get_random_bytes(ndev->entropy, sizeof(ndev->entropy)); 389 ndev->regen_timer.function = ipv6_regen_rndid;
376 init_timer(&ndev->regen_timer); 390 ndev->regen_timer.data = (unsigned long) ndev;
377 ndev->regen_timer.function = ipv6_regen_rndid; 391 if ((dev->flags&IFF_LOOPBACK) ||
378 ndev->regen_timer.data = (unsigned long) ndev; 392 dev->type == ARPHRD_TUNNEL ||
379 if ((dev->flags&IFF_LOOPBACK) || 393 dev->type == ARPHRD_NONE ||
380 dev->type == ARPHRD_TUNNEL || 394 dev->type == ARPHRD_SIT) {
381 dev->type == ARPHRD_NONE || 395 printk(KERN_INFO
382 dev->type == ARPHRD_SIT) { 396 "%s: Disabled Privacy Extensions\n",
383 printk(KERN_INFO 397 dev->name);
384 "%s: Disabled Privacy Extensions\n", 398 ndev->cnf.use_tempaddr = -1;
385 dev->name); 399 } else {
386 ndev->cnf.use_tempaddr = -1; 400 in6_dev_hold(ndev);
387 } else { 401 ipv6_regen_rndid((unsigned long) ndev);
388 in6_dev_hold(ndev); 402 }
389 ipv6_regen_rndid((unsigned long) ndev);
390 }
391#endif 403#endif
392 404
393 if (netif_carrier_ok(dev)) 405 if (netif_carrier_ok(dev))
394 ndev->if_flags |= IF_READY; 406 ndev->if_flags |= IF_READY;
395 407
396 write_lock_bh(&addrconf_lock); 408 write_lock_bh(&addrconf_lock);
397 dev->ip6_ptr = ndev; 409 dev->ip6_ptr = ndev;
398 write_unlock_bh(&addrconf_lock); 410 write_unlock_bh(&addrconf_lock);
399 411
400 ipv6_mc_init_dev(ndev); 412 ipv6_mc_init_dev(ndev);
401 ndev->tstamp = jiffies; 413 ndev->tstamp = jiffies;
402#ifdef CONFIG_SYSCTL 414#ifdef CONFIG_SYSCTL
403 neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, 415 neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6,
404 NET_IPV6_NEIGH, "ipv6", 416 NET_IPV6_NEIGH, "ipv6",
405 &ndisc_ifinfo_sysctl_change, 417 &ndisc_ifinfo_sysctl_change,
406 NULL); 418 NULL);
407 addrconf_sysctl_register(ndev, &ndev->cnf); 419 addrconf_sysctl_register(ndev, &ndev->cnf);
408#endif 420#endif
409 }
410 return ndev; 421 return ndev;
411} 422}
412 423
@@ -524,7 +535,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
524 goto out; 535 goto out;
525 } 536 }
526 537
527 ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); 538 ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
528 539
529 if (ifa == NULL) { 540 if (ifa == NULL) {
530 ADBG(("ipv6_add_addr: malloc failed\n")); 541 ADBG(("ipv6_add_addr: malloc failed\n"));
@@ -538,7 +549,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
538 goto out; 549 goto out;
539 } 550 }
540 551
541 memset(ifa, 0, sizeof(struct inet6_ifaddr));
542 ipv6_addr_copy(&ifa->addr, addr); 552 ipv6_addr_copy(&ifa->addr, addr);
543 553
544 spin_lock_init(&ifa->lock); 554 spin_lock_init(&ifa->lock);
@@ -1305,52 +1315,67 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
1305 __ipv6_dev_ac_dec(ifp->idev, &addr); 1315 __ipv6_dev_ac_dec(ifp->idev, &addr);
1306} 1316}
1307 1317
1318static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
1319{
1320 if (dev->addr_len != ETH_ALEN)
1321 return -1;
1322 memcpy(eui, dev->dev_addr, 3);
1323 memcpy(eui + 5, dev->dev_addr + 3, 3);
1324
1325 /*
1326 * The zSeries OSA network cards can be shared among various
1327 * OS instances, but the OSA cards have only one MAC address.
1328 * This leads to duplicate address conflicts in conjunction
1329 * with IPv6 if more than one instance uses the same card.
1330 *
1331 * The driver for these cards can deliver a unique 16-bit
1332 * identifier for each instance sharing the same card. It is
1333 * placed instead of 0xFFFE in the interface identifier. The
1334 * "u" bit of the interface identifier is not inverted in this
1335 * case. Hence the resulting interface identifier has local
1336 * scope according to RFC2373.
1337 */
1338 if (dev->dev_id) {
1339 eui[3] = (dev->dev_id >> 8) & 0xFF;
1340 eui[4] = dev->dev_id & 0xFF;
1341 } else {
1342 eui[3] = 0xFF;
1343 eui[4] = 0xFE;
1344 eui[0] ^= 2;
1345 }
1346 return 0;
1347}
1348
1349static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
1350{
1351 /* XXX: inherit EUI-64 from other interface -- yoshfuji */
1352 if (dev->addr_len != ARCNET_ALEN)
1353 return -1;
1354 memset(eui, 0, 7);
1355 eui[7] = *(u8*)dev->dev_addr;
1356 return 0;
1357}
1358
1359static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev)
1360{
1361 if (dev->addr_len != INFINIBAND_ALEN)
1362 return -1;
1363 memcpy(eui, dev->dev_addr + 12, 8);
1364 eui[0] |= 2;
1365 return 0;
1366}
1367
1308static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) 1368static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
1309{ 1369{
1310 switch (dev->type) { 1370 switch (dev->type) {
1311 case ARPHRD_ETHER: 1371 case ARPHRD_ETHER:
1312 case ARPHRD_FDDI: 1372 case ARPHRD_FDDI:
1313 case ARPHRD_IEEE802_TR: 1373 case ARPHRD_IEEE802_TR:
1314 if (dev->addr_len != ETH_ALEN) 1374 return addrconf_ifid_eui48(eui, dev);
1315 return -1;
1316 memcpy(eui, dev->dev_addr, 3);
1317 memcpy(eui + 5, dev->dev_addr + 3, 3);
1318
1319 /*
1320 * The zSeries OSA network cards can be shared among various
1321 * OS instances, but the OSA cards have only one MAC address.
1322 * This leads to duplicate address conflicts in conjunction
1323 * with IPv6 if more than one instance uses the same card.
1324 *
1325 * The driver for these cards can deliver a unique 16-bit
1326 * identifier for each instance sharing the same card. It is
1327 * placed instead of 0xFFFE in the interface identifier. The
1328 * "u" bit of the interface identifier is not inverted in this
1329 * case. Hence the resulting interface identifier has local
1330 * scope according to RFC2373.
1331 */
1332 if (dev->dev_id) {
1333 eui[3] = (dev->dev_id >> 8) & 0xFF;
1334 eui[4] = dev->dev_id & 0xFF;
1335 } else {
1336 eui[3] = 0xFF;
1337 eui[4] = 0xFE;
1338 eui[0] ^= 2;
1339 }
1340 return 0;
1341 case ARPHRD_ARCNET: 1375 case ARPHRD_ARCNET:
1342 /* XXX: inherit EUI-64 from other interface -- yoshfuji */ 1376 return addrconf_ifid_arcnet(eui, dev);
1343 if (dev->addr_len != ARCNET_ALEN)
1344 return -1;
1345 memset(eui, 0, 7);
1346 eui[7] = *(u8*)dev->dev_addr;
1347 return 0;
1348 case ARPHRD_INFINIBAND: 1377 case ARPHRD_INFINIBAND:
1349 if (dev->addr_len != INFINIBAND_ALEN) 1378 return addrconf_ifid_infiniband(eui, dev);
1350 return -1;
1351 memcpy(eui, dev->dev_addr + 12, 8);
1352 eui[0] |= 2;
1353 return 0;
1354 } 1379 }
1355 return -1; 1380 return -1;
1356} 1381}
@@ -1376,34 +1401,9 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
1376/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ 1401/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
1377static int __ipv6_regen_rndid(struct inet6_dev *idev) 1402static int __ipv6_regen_rndid(struct inet6_dev *idev)
1378{ 1403{
1379 struct net_device *dev;
1380 struct scatterlist sg[2];
1381
1382 sg_set_buf(&sg[0], idev->entropy, 8);
1383 sg_set_buf(&sg[1], idev->work_eui64, 8);
1384
1385 dev = idev->dev;
1386
1387 if (ipv6_generate_eui64(idev->work_eui64, dev)) {
1388 printk(KERN_INFO
1389 "__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",
1390 idev);
1391 get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64));
1392 }
1393regen: 1404regen:
1394 spin_lock(&md5_tfm_lock); 1405 get_random_bytes(idev->rndid, sizeof(idev->rndid));
1395 if (unlikely(md5_tfm == NULL)) {
1396 spin_unlock(&md5_tfm_lock);
1397 return -1;
1398 }
1399 crypto_digest_init(md5_tfm);
1400 crypto_digest_update(md5_tfm, sg, 2);
1401 crypto_digest_final(md5_tfm, idev->work_digest);
1402 spin_unlock(&md5_tfm_lock);
1403
1404 memcpy(idev->rndid, &idev->work_digest[0], 8);
1405 idev->rndid[0] &= ~0x02; 1406 idev->rndid[0] &= ~0x02;
1406 memcpy(idev->entropy, &idev->work_digest[8], 8);
1407 1407
1408 /* 1408 /*
1409 * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>: 1409 * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
@@ -2143,7 +2143,6 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
2143 return; 2143 return;
2144 } 2144 }
2145 ip6_tnl_add_linklocal(idev); 2145 ip6_tnl_add_linklocal(idev);
2146 addrconf_add_mroute(dev);
2147} 2146}
2148 2147
2149static int addrconf_notify(struct notifier_block *this, unsigned long event, 2148static int addrconf_notify(struct notifier_block *this, unsigned long event,
@@ -2668,11 +2667,10 @@ static int if6_seq_open(struct inode *inode, struct file *file)
2668{ 2667{
2669 struct seq_file *seq; 2668 struct seq_file *seq;
2670 int rc = -ENOMEM; 2669 int rc = -ENOMEM;
2671 struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); 2670 struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
2672 2671
2673 if (!s) 2672 if (!s)
2674 goto out; 2673 goto out;
2675 memset(s, 0, sizeof(*s));
2676 2674
2677 rc = seq_open(file, &if6_seq_ops); 2675 rc = seq_open(file, &if6_seq_ops);
2678 if (rc) 2676 if (rc)
@@ -3133,6 +3131,15 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
3133 array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; 3131 array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
3134#endif 3132#endif
3135 array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; 3133 array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
3134 array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
3135 array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
3136#ifdef CONFIG_IPV6_ROUTER_PREF
3137 array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
3138 array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
3139#ifdef CONFIV_IPV6_ROUTE_INFO
3140 array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
3141#endif
3142#endif
3136} 3143}
3137 3144
3138static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, 3145static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
@@ -3586,6 +3593,51 @@ static struct addrconf_sysctl_table
3586 .proc_handler = &proc_dointvec, 3593 .proc_handler = &proc_dointvec,
3587 }, 3594 },
3588 { 3595 {
3596 .ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR,
3597 .procname = "accept_ra_defrtr",
3598 .data = &ipv6_devconf.accept_ra_defrtr,
3599 .maxlen = sizeof(int),
3600 .mode = 0644,
3601 .proc_handler = &proc_dointvec,
3602 },
3603 {
3604 .ctl_name = NET_IPV6_ACCEPT_RA_PINFO,
3605 .procname = "accept_ra_pinfo",
3606 .data = &ipv6_devconf.accept_ra_pinfo,
3607 .maxlen = sizeof(int),
3608 .mode = 0644,
3609 .proc_handler = &proc_dointvec,
3610 },
3611#ifdef CONFIG_IPV6_ROUTER_PREF
3612 {
3613 .ctl_name = NET_IPV6_ACCEPT_RA_RTR_PREF,
3614 .procname = "accept_ra_rtr_pref",
3615 .data = &ipv6_devconf.accept_ra_rtr_pref,
3616 .maxlen = sizeof(int),
3617 .mode = 0644,
3618 .proc_handler = &proc_dointvec,
3619 },
3620 {
3621 .ctl_name = NET_IPV6_RTR_PROBE_INTERVAL,
3622 .procname = "router_probe_interval",
3623 .data = &ipv6_devconf.rtr_probe_interval,
3624 .maxlen = sizeof(int),
3625 .mode = 0644,
3626 .proc_handler = &proc_dointvec_jiffies,
3627 .strategy = &sysctl_jiffies,
3628 },
3629#ifdef CONFIV_IPV6_ROUTE_INFO
3630 {
3631 .ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
3632 .procname = "accept_ra_rt_info_max_plen",
3633 .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
3634 .maxlen = sizeof(int),
3635 .mode = 0644,
3636 .proc_handler = &proc_dointvec,
3637 },
3638#endif
3639#endif
3640 {
3589 .ctl_name = 0, /* sentinel */ 3641 .ctl_name = 0, /* sentinel */
3590 } 3642 }
3591 }, 3643 },
@@ -3760,13 +3812,6 @@ int __init addrconf_init(void)
3760 3812
3761 register_netdevice_notifier(&ipv6_dev_notf); 3813 register_netdevice_notifier(&ipv6_dev_notf);
3762 3814
3763#ifdef CONFIG_IPV6_PRIVACY
3764 md5_tfm = crypto_alloc_tfm("md5", 0);
3765 if (unlikely(md5_tfm == NULL))
3766 printk(KERN_WARNING
3767 "failed to load transform for md5\n");
3768#endif
3769
3770 addrconf_verify(0); 3815 addrconf_verify(0);
3771 rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; 3816 rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
3772#ifdef CONFIG_SYSCTL 3817#ifdef CONFIG_SYSCTL
@@ -3829,11 +3874,6 @@ void __exit addrconf_cleanup(void)
3829 3874
3830 rtnl_unlock(); 3875 rtnl_unlock();
3831 3876
3832#ifdef CONFIG_IPV6_PRIVACY
3833 crypto_free_tfm(md5_tfm);
3834 md5_tfm = NULL;
3835#endif
3836
3837#ifdef CONFIG_PROC_FS 3877#ifdef CONFIG_PROC_FS
3838 proc_net_remove("if_inet6"); 3878 proc_net_remove("if_inet6");
3839#endif 3879#endif
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 6c9711ac1c03..e19457fe4f6e 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -456,45 +456,53 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
456} 456}
457 457
458const struct proto_ops inet6_stream_ops = { 458const struct proto_ops inet6_stream_ops = {
459 .family = PF_INET6, 459 .family = PF_INET6,
460 .owner = THIS_MODULE, 460 .owner = THIS_MODULE,
461 .release = inet6_release, 461 .release = inet6_release,
462 .bind = inet6_bind, 462 .bind = inet6_bind,
463 .connect = inet_stream_connect, /* ok */ 463 .connect = inet_stream_connect, /* ok */
464 .socketpair = sock_no_socketpair, /* a do nothing */ 464 .socketpair = sock_no_socketpair, /* a do nothing */
465 .accept = inet_accept, /* ok */ 465 .accept = inet_accept, /* ok */
466 .getname = inet6_getname, 466 .getname = inet6_getname,
467 .poll = tcp_poll, /* ok */ 467 .poll = tcp_poll, /* ok */
468 .ioctl = inet6_ioctl, /* must change */ 468 .ioctl = inet6_ioctl, /* must change */
469 .listen = inet_listen, /* ok */ 469 .listen = inet_listen, /* ok */
470 .shutdown = inet_shutdown, /* ok */ 470 .shutdown = inet_shutdown, /* ok */
471 .setsockopt = sock_common_setsockopt, /* ok */ 471 .setsockopt = sock_common_setsockopt, /* ok */
472 .getsockopt = sock_common_getsockopt, /* ok */ 472 .getsockopt = sock_common_getsockopt, /* ok */
473 .sendmsg = inet_sendmsg, /* ok */ 473 .sendmsg = inet_sendmsg, /* ok */
474 .recvmsg = sock_common_recvmsg, /* ok */ 474 .recvmsg = sock_common_recvmsg, /* ok */
475 .mmap = sock_no_mmap, 475 .mmap = sock_no_mmap,
476 .sendpage = tcp_sendpage 476 .sendpage = tcp_sendpage,
477#ifdef CONFIG_COMPAT
478 .compat_setsockopt = compat_sock_common_setsockopt,
479 .compat_getsockopt = compat_sock_common_getsockopt,
480#endif
477}; 481};
478 482
479const struct proto_ops inet6_dgram_ops = { 483const struct proto_ops inet6_dgram_ops = {
480 .family = PF_INET6, 484 .family = PF_INET6,
481 .owner = THIS_MODULE, 485 .owner = THIS_MODULE,
482 .release = inet6_release, 486 .release = inet6_release,
483 .bind = inet6_bind, 487 .bind = inet6_bind,
484 .connect = inet_dgram_connect, /* ok */ 488 .connect = inet_dgram_connect, /* ok */
485 .socketpair = sock_no_socketpair, /* a do nothing */ 489 .socketpair = sock_no_socketpair, /* a do nothing */
486 .accept = sock_no_accept, /* a do nothing */ 490 .accept = sock_no_accept, /* a do nothing */
487 .getname = inet6_getname, 491 .getname = inet6_getname,
488 .poll = udp_poll, /* ok */ 492 .poll = udp_poll, /* ok */
489 .ioctl = inet6_ioctl, /* must change */ 493 .ioctl = inet6_ioctl, /* must change */
490 .listen = sock_no_listen, /* ok */ 494 .listen = sock_no_listen, /* ok */
491 .shutdown = inet_shutdown, /* ok */ 495 .shutdown = inet_shutdown, /* ok */
492 .setsockopt = sock_common_setsockopt, /* ok */ 496 .setsockopt = sock_common_setsockopt, /* ok */
493 .getsockopt = sock_common_getsockopt, /* ok */ 497 .getsockopt = sock_common_getsockopt, /* ok */
494 .sendmsg = inet_sendmsg, /* ok */ 498 .sendmsg = inet_sendmsg, /* ok */
495 .recvmsg = sock_common_recvmsg, /* ok */ 499 .recvmsg = sock_common_recvmsg, /* ok */
496 .mmap = sock_no_mmap, 500 .mmap = sock_no_mmap,
497 .sendpage = sock_no_sendpage, 501 .sendpage = sock_no_sendpage,
502#ifdef CONFIG_COMPAT
503 .compat_setsockopt = compat_sock_common_setsockopt,
504 .compat_getsockopt = compat_sock_common_getsockopt,
505#endif
498}; 506};
499 507
500static struct net_proto_family inet6_family_ops = { 508static struct net_proto_family inet6_family_ops = {
@@ -505,24 +513,28 @@ static struct net_proto_family inet6_family_ops = {
505 513
506/* Same as inet6_dgram_ops, sans udp_poll. */ 514/* Same as inet6_dgram_ops, sans udp_poll. */
507static const struct proto_ops inet6_sockraw_ops = { 515static const struct proto_ops inet6_sockraw_ops = {
508 .family = PF_INET6, 516 .family = PF_INET6,
509 .owner = THIS_MODULE, 517 .owner = THIS_MODULE,
510 .release = inet6_release, 518 .release = inet6_release,
511 .bind = inet6_bind, 519 .bind = inet6_bind,
512 .connect = inet_dgram_connect, /* ok */ 520 .connect = inet_dgram_connect, /* ok */
513 .socketpair = sock_no_socketpair, /* a do nothing */ 521 .socketpair = sock_no_socketpair, /* a do nothing */
514 .accept = sock_no_accept, /* a do nothing */ 522 .accept = sock_no_accept, /* a do nothing */
515 .getname = inet6_getname, 523 .getname = inet6_getname,
516 .poll = datagram_poll, /* ok */ 524 .poll = datagram_poll, /* ok */
517 .ioctl = inet6_ioctl, /* must change */ 525 .ioctl = inet6_ioctl, /* must change */
518 .listen = sock_no_listen, /* ok */ 526 .listen = sock_no_listen, /* ok */
519 .shutdown = inet_shutdown, /* ok */ 527 .shutdown = inet_shutdown, /* ok */
520 .setsockopt = sock_common_setsockopt, /* ok */ 528 .setsockopt = sock_common_setsockopt, /* ok */
521 .getsockopt = sock_common_getsockopt, /* ok */ 529 .getsockopt = sock_common_getsockopt, /* ok */
522 .sendmsg = inet_sendmsg, /* ok */ 530 .sendmsg = inet_sendmsg, /* ok */
523 .recvmsg = sock_common_recvmsg, /* ok */ 531 .recvmsg = sock_common_recvmsg, /* ok */
524 .mmap = sock_no_mmap, 532 .mmap = sock_no_mmap,
525 .sendpage = sock_no_sendpage, 533 .sendpage = sock_no_sendpage,
534#ifdef CONFIG_COMPAT
535 .compat_setsockopt = compat_sock_common_setsockopt,
536 .compat_getsockopt = compat_sock_common_getsockopt,
537#endif
526}; 538};
527 539
528static struct inet_protosw rawv6_protosw = { 540static struct inet_protosw rawv6_protosw = {
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 84963749ab77..cf58251df4b3 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -213,6 +213,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
213 ah->reserved = 0; 213 ah->reserved = 0;
214 ah->spi = x->id.spi; 214 ah->spi = x->id.spi;
215 ah->seq_no = htonl(++x->replay.oseq); 215 ah->seq_no = htonl(++x->replay.oseq);
216 xfrm_aevent_doreplay(x);
216 ahp->icv(ahp, skb, ah->auth_data); 217 ahp->icv(ahp, skb, ah->auth_data);
217 218
218 err = 0; 219 err = 0;
@@ -353,12 +354,10 @@ static int ah6_init_state(struct xfrm_state *x)
353 if (x->encap) 354 if (x->encap)
354 goto error; 355 goto error;
355 356
356 ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); 357 ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
357 if (ahp == NULL) 358 if (ahp == NULL)
358 return -ENOMEM; 359 return -ENOMEM;
359 360
360 memset(ahp, 0, sizeof(*ahp));
361
362 ahp->key = x->aalg->alg_key; 361 ahp->key = x->aalg->alg_key;
363 ahp->key_len = (x->aalg->alg_key_len+7)/8; 362 ahp->key_len = (x->aalg->alg_key_len+7)/8;
364 ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); 363 ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 840a33d33296..39ec528923f6 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -308,7 +308,7 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
308 * not found: create a new one. 308 * not found: create a new one.
309 */ 309 */
310 310
311 aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); 311 aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
312 312
313 if (aca == NULL) { 313 if (aca == NULL) {
314 err = -ENOMEM; 314 err = -ENOMEM;
@@ -322,8 +322,6 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
322 goto out; 322 goto out;
323 } 323 }
324 324
325 memset(aca, 0, sizeof(struct ifacaddr6));
326
327 ipv6_addr_copy(&aca->aca_addr, addr); 325 ipv6_addr_copy(&aca->aca_addr, addr);
328 aca->aca_idev = idev; 326 aca->aca_idev = idev;
329 aca->aca_rt = rt; 327 aca->aca_rt = rt;
@@ -550,7 +548,7 @@ static int ac6_seq_open(struct inode *inode, struct file *file)
550{ 548{
551 struct seq_file *seq; 549 struct seq_file *seq;
552 int rc = -ENOMEM; 550 int rc = -ENOMEM;
553 struct ac6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); 551 struct ac6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
554 552
555 if (!s) 553 if (!s)
556 goto out; 554 goto out;
@@ -561,7 +559,6 @@ static int ac6_seq_open(struct inode *inode, struct file *file)
561 559
562 seq = file->private_data; 560 seq = file->private_data;
563 seq->private = s; 561 seq->private = s;
564 memset(s, 0, sizeof(*s));
565out: 562out:
566 return rc; 563 return rc;
567out_kfree: 564out_kfree:
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 7b5b94f13902..3dcaac7a0972 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -94,6 +94,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
94 94
95 esph->spi = x->id.spi; 95 esph->spi = x->id.spi;
96 esph->seq_no = htonl(++x->replay.oseq); 96 esph->seq_no = htonl(++x->replay.oseq);
97 xfrm_aevent_doreplay(x);
97 98
98 if (esp->conf.ivlen) 99 if (esp->conf.ivlen)
99 crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); 100 crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
@@ -304,12 +305,10 @@ static int esp6_init_state(struct xfrm_state *x)
304 if (x->encap) 305 if (x->encap)
305 goto error; 306 goto error;
306 307
307 esp = kmalloc(sizeof(*esp), GFP_KERNEL); 308 esp = kzalloc(sizeof(*esp), GFP_KERNEL);
308 if (esp == NULL) 309 if (esp == NULL)
309 return -ENOMEM; 310 return -ENOMEM;
310 311
311 memset(esp, 0, sizeof(*esp));
312
313 if (x->aalg) { 312 if (x->aalg) {
314 struct xfrm_algo_desc *aalg_desc; 313 struct xfrm_algo_desc *aalg_desc;
315 314
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 1bf6d9a769e6..2cb6149349bf 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1105,7 +1105,6 @@ static int fib6_age(struct rt6_info *rt, void *arg)
1105 if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) { 1105 if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) {
1106 if (time_after(now, rt->rt6i_expires)) { 1106 if (time_after(now, rt->rt6i_expires)) {
1107 RT6_TRACE("expiring %p\n", rt); 1107 RT6_TRACE("expiring %p\n", rt);
1108 rt6_reset_dflt_pointer(rt);
1109 return -1; 1108 return -1;
1110 } 1109 }
1111 gc_args.more++; 1110 gc_args.more++;
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 69cbe8a66d02..f9ca63912fbf 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -287,10 +287,9 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
287 int err; 287 int err;
288 288
289 err = -ENOMEM; 289 err = -ENOMEM;
290 fl = kmalloc(sizeof(*fl), GFP_KERNEL); 290 fl = kzalloc(sizeof(*fl), GFP_KERNEL);
291 if (fl == NULL) 291 if (fl == NULL)
292 goto done; 292 goto done;
293 memset(fl, 0, sizeof(*fl));
294 293
295 olen = optlen - CMSG_ALIGN(sizeof(*freq)); 294 olen = optlen - CMSG_ALIGN(sizeof(*freq));
296 if (olen > 0) { 295 if (olen > 0) {
@@ -663,7 +662,7 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file)
663{ 662{
664 struct seq_file *seq; 663 struct seq_file *seq;
665 int rc = -ENOMEM; 664 int rc = -ENOMEM;
666 struct ip6fl_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); 665 struct ip6fl_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
667 666
668 if (!s) 667 if (!s)
669 goto out; 668 goto out;
@@ -674,7 +673,6 @@ static int ip6fl_seq_open(struct inode *inode, struct file *file)
674 673
675 seq = file->private_data; 674 seq = file->private_data;
676 seq->private = s; 675 seq->private = s;
677 memset(s, 0, sizeof(*s));
678out: 676out:
679 return rc; 677 return rc;
680out_kfree: 678out_kfree:
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5bf70b1442ea..4fbc40b13f19 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -733,28 +733,29 @@ int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
733 if (*dst) { 733 if (*dst) {
734 struct rt6_info *rt = (struct rt6_info*)*dst; 734 struct rt6_info *rt = (struct rt6_info*)*dst;
735 735
736 /* Yes, checking route validity in not connected 736 /* Yes, checking route validity in not connected
737 case is not very simple. Take into account, 737 * case is not very simple. Take into account,
738 that we do not support routing by source, TOS, 738 * that we do not support routing by source, TOS,
739 and MSG_DONTROUTE --ANK (980726) 739 * and MSG_DONTROUTE --ANK (980726)
740 740 *
741 1. If route was host route, check that 741 * 1. If route was host route, check that
742 cached destination is current. 742 * cached destination is current.
743 If it is network route, we still may 743 * If it is network route, we still may
744 check its validity using saved pointer 744 * check its validity using saved pointer
745 to the last used address: daddr_cache. 745 * to the last used address: daddr_cache.
746 We do not want to save whole address now, 746 * We do not want to save whole address now,
747 (because main consumer of this service 747 * (because main consumer of this service
748 is tcp, which has not this problem), 748 * is tcp, which has not this problem),
749 so that the last trick works only on connected 749 * so that the last trick works only on connected
750 sockets. 750 * sockets.
751 2. oif also should be the same. 751 * 2. oif also should be the same.
752 */ 752 */
753
754 if (((rt->rt6i_dst.plen != 128 || 753 if (((rt->rt6i_dst.plen != 128 ||
755 !ipv6_addr_equal(&fl->fl6_dst, &rt->rt6i_dst.addr)) 754 !ipv6_addr_equal(&fl->fl6_dst,
755 &rt->rt6i_dst.addr))
756 && (np->daddr_cache == NULL || 756 && (np->daddr_cache == NULL ||
757 !ipv6_addr_equal(&fl->fl6_dst, np->daddr_cache))) 757 !ipv6_addr_equal(&fl->fl6_dst,
758 np->daddr_cache)))
758 || (fl->oif && fl->oif != (*dst)->dev->ifindex)) { 759 || (fl->oif && fl->oif != (*dst)->dev->ifindex)) {
759 dst_release(*dst); 760 dst_release(*dst);
760 *dst = NULL; 761 *dst = NULL;
@@ -889,7 +890,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
889 np->cork.hop_limit = hlimit; 890 np->cork.hop_limit = hlimit;
890 np->cork.tclass = tclass; 891 np->cork.tclass = tclass;
891 mtu = dst_mtu(rt->u.dst.path); 892 mtu = dst_mtu(rt->u.dst.path);
892 if (np && np->frag_size < mtu) { 893 if (np->frag_size < mtu) {
893 if (np->frag_size) 894 if (np->frag_size)
894 mtu = np->frag_size; 895 mtu = np->frag_size;
895 } 896 }
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index d511a884dad0..028b636687ec 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -50,6 +50,7 @@
50#include <net/protocol.h> 50#include <net/protocol.h>
51#include <linux/ipv6.h> 51#include <linux/ipv6.h>
52#include <linux/icmpv6.h> 52#include <linux/icmpv6.h>
53#include <linux/mutex.h>
53 54
54struct ipcomp6_tfms { 55struct ipcomp6_tfms {
55 struct list_head list; 56 struct list_head list;
@@ -57,7 +58,7 @@ struct ipcomp6_tfms {
57 int users; 58 int users;
58}; 59};
59 60
60static DECLARE_MUTEX(ipcomp6_resource_sem); 61static DEFINE_MUTEX(ipcomp6_resource_mutex);
61static void **ipcomp6_scratches; 62static void **ipcomp6_scratches;
62static int ipcomp6_scratch_users; 63static int ipcomp6_scratch_users;
63static LIST_HEAD(ipcomp6_tfms_list); 64static LIST_HEAD(ipcomp6_tfms_list);
@@ -286,8 +287,8 @@ static void ipcomp6_free_scratches(void)
286 287
287 for_each_cpu(i) { 288 for_each_cpu(i) {
288 void *scratch = *per_cpu_ptr(scratches, i); 289 void *scratch = *per_cpu_ptr(scratches, i);
289 if (scratch) 290
290 vfree(scratch); 291 vfree(scratch);
291 } 292 }
292 293
293 free_percpu(scratches); 294 free_percpu(scratches);
@@ -405,9 +406,9 @@ static void ipcomp6_destroy(struct xfrm_state *x)
405 if (!ipcd) 406 if (!ipcd)
406 return; 407 return;
407 xfrm_state_delete_tunnel(x); 408 xfrm_state_delete_tunnel(x);
408 down(&ipcomp6_resource_sem); 409 mutex_lock(&ipcomp6_resource_mutex);
409 ipcomp6_free_data(ipcd); 410 ipcomp6_free_data(ipcd);
410 up(&ipcomp6_resource_sem); 411 mutex_unlock(&ipcomp6_resource_mutex);
411 kfree(ipcd); 412 kfree(ipcd);
412 413
413 xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); 414 xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
@@ -427,23 +428,22 @@ static int ipcomp6_init_state(struct xfrm_state *x)
427 goto out; 428 goto out;
428 429
429 err = -ENOMEM; 430 err = -ENOMEM;
430 ipcd = kmalloc(sizeof(*ipcd), GFP_KERNEL); 431 ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL);
431 if (!ipcd) 432 if (!ipcd)
432 goto out; 433 goto out;
433 434
434 memset(ipcd, 0, sizeof(*ipcd));
435 x->props.header_len = 0; 435 x->props.header_len = 0;
436 if (x->props.mode) 436 if (x->props.mode)
437 x->props.header_len += sizeof(struct ipv6hdr); 437 x->props.header_len += sizeof(struct ipv6hdr);
438 438
439 down(&ipcomp6_resource_sem); 439 mutex_lock(&ipcomp6_resource_mutex);
440 if (!ipcomp6_alloc_scratches()) 440 if (!ipcomp6_alloc_scratches())
441 goto error; 441 goto error;
442 442
443 ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name); 443 ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name);
444 if (!ipcd->tfms) 444 if (!ipcd->tfms)
445 goto error; 445 goto error;
446 up(&ipcomp6_resource_sem); 446 mutex_unlock(&ipcomp6_resource_mutex);
447 447
448 if (x->props.mode) { 448 if (x->props.mode) {
449 err = ipcomp6_tunnel_attach(x); 449 err = ipcomp6_tunnel_attach(x);
@@ -459,10 +459,10 @@ static int ipcomp6_init_state(struct xfrm_state *x)
459out: 459out:
460 return err; 460 return err;
461error_tunnel: 461error_tunnel:
462 down(&ipcomp6_resource_sem); 462 mutex_lock(&ipcomp6_resource_mutex);
463error: 463error:
464 ipcomp6_free_data(ipcd); 464 ipcomp6_free_data(ipcd);
465 up(&ipcomp6_resource_sem); 465 mutex_unlock(&ipcomp6_resource_mutex);
466 kfree(ipcd); 466 kfree(ipcd);
467 467
468 goto out; 468 goto out;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index f7142ba519ab..602feec47738 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -109,19 +109,13 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
109 return 0; 109 return 0;
110} 110}
111 111
112int ipv6_setsockopt(struct sock *sk, int level, int optname, 112static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
113 char __user *optval, int optlen) 113 char __user *optval, int optlen)
114{ 114{
115 struct ipv6_pinfo *np = inet6_sk(sk); 115 struct ipv6_pinfo *np = inet6_sk(sk);
116 int val, valbool; 116 int val, valbool;
117 int retv = -ENOPROTOOPT; 117 int retv = -ENOPROTOOPT;
118 118
119 if (level == SOL_IP && sk->sk_type != SOCK_RAW)
120 return udp_prot.setsockopt(sk, level, optname, optval, optlen);
121
122 if(level!=SOL_IPV6)
123 goto out;
124
125 if (optval == NULL) 119 if (optval == NULL)
126 val=0; 120 val=0;
127 else if (get_user(val, (int __user *) optval)) 121 else if (get_user(val, (int __user *) optval))
@@ -613,17 +607,9 @@ done:
613 retv = xfrm_user_policy(sk, optname, optval, optlen); 607 retv = xfrm_user_policy(sk, optname, optval, optlen);
614 break; 608 break;
615 609
616#ifdef CONFIG_NETFILTER
617 default:
618 retv = nf_setsockopt(sk, PF_INET6, optname, optval,
619 optlen);
620 break;
621#endif
622
623 } 610 }
624 release_sock(sk); 611 release_sock(sk);
625 612
626out:
627 return retv; 613 return retv;
628 614
629e_inval: 615e_inval:
@@ -631,6 +617,65 @@ e_inval:
631 return -EINVAL; 617 return -EINVAL;
632} 618}
633 619
620int ipv6_setsockopt(struct sock *sk, int level, int optname,
621 char __user *optval, int optlen)
622{
623 int err;
624
625 if (level == SOL_IP && sk->sk_type != SOCK_RAW)
626 return udp_prot.setsockopt(sk, level, optname, optval, optlen);
627
628 if (level != SOL_IPV6)
629 return -ENOPROTOOPT;
630
631 err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
632#ifdef CONFIG_NETFILTER
633 /* we need to exclude all possible ENOPROTOOPTs except default case */
634 if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
635 optname != IPV6_XFRM_POLICY) {
636 lock_sock(sk);
637 err = nf_setsockopt(sk, PF_INET6, optname, optval,
638 optlen);
639 release_sock(sk);
640 }
641#endif
642 return err;
643}
644
645
646#ifdef CONFIG_COMPAT
647int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
648 char __user *optval, int optlen)
649{
650 int err;
651
652 if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
653 if (udp_prot.compat_setsockopt != NULL)
654 return udp_prot.compat_setsockopt(sk, level, optname,
655 optval, optlen);
656 return udp_prot.setsockopt(sk, level, optname, optval, optlen);
657 }
658
659 if (level != SOL_IPV6)
660 return -ENOPROTOOPT;
661
662 err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
663#ifdef CONFIG_NETFILTER
664 /* we need to exclude all possible ENOPROTOOPTs except default case */
665 if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
666 optname != IPV6_XFRM_POLICY) {
667 lock_sock(sk);
668 err = compat_nf_setsockopt(sk, PF_INET6, optname,
669 optval, optlen);
670 release_sock(sk);
671 }
672#endif
673 return err;
674}
675
676EXPORT_SYMBOL(compat_ipv6_setsockopt);
677#endif
678
634static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, 679static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr,
635 char __user *optval, int len) 680 char __user *optval, int len)
636{ 681{
@@ -642,17 +687,13 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr,
642 return len; 687 return len;
643} 688}
644 689
645int ipv6_getsockopt(struct sock *sk, int level, int optname, 690static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
646 char __user *optval, int __user *optlen) 691 char __user *optval, int __user *optlen)
647{ 692{
648 struct ipv6_pinfo *np = inet6_sk(sk); 693 struct ipv6_pinfo *np = inet6_sk(sk);
649 int len; 694 int len;
650 int val; 695 int val;
651 696
652 if (level == SOL_IP && sk->sk_type != SOCK_RAW)
653 return udp_prot.getsockopt(sk, level, optname, optval, optlen);
654 if(level!=SOL_IPV6)
655 return -ENOPROTOOPT;
656 if (get_user(len, optlen)) 697 if (get_user(len, optlen))
657 return -EFAULT; 698 return -EFAULT;
658 switch (optname) { 699 switch (optname) {
@@ -842,17 +883,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
842 break; 883 break;
843 884
844 default: 885 default:
845#ifdef CONFIG_NETFILTER
846 lock_sock(sk);
847 val = nf_getsockopt(sk, PF_INET6, optname, optval,
848 &len);
849 release_sock(sk);
850 if (val >= 0)
851 val = put_user(len, optlen);
852 return val;
853#else
854 return -EINVAL; 886 return -EINVAL;
855#endif
856 } 887 }
857 len = min_t(unsigned int, sizeof(int), len); 888 len = min_t(unsigned int, sizeof(int), len);
858 if(put_user(len, optlen)) 889 if(put_user(len, optlen))
@@ -862,6 +893,78 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
862 return 0; 893 return 0;
863} 894}
864 895
896int ipv6_getsockopt(struct sock *sk, int level, int optname,
897 char __user *optval, int __user *optlen)
898{
899 int err;
900
901 if (level == SOL_IP && sk->sk_type != SOCK_RAW)
902 return udp_prot.getsockopt(sk, level, optname, optval, optlen);
903
904 if(level != SOL_IPV6)
905 return -ENOPROTOOPT;
906
907 err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
908#ifdef CONFIG_NETFILTER
909 /* we need to exclude all possible EINVALs except default case */
910 if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM &&
911 optname != MCAST_MSFILTER) {
912 int len;
913
914 if (get_user(len, optlen))
915 return -EFAULT;
916
917 lock_sock(sk);
918 err = nf_getsockopt(sk, PF_INET6, optname, optval,
919 &len);
920 release_sock(sk);
921 if (err >= 0)
922 err = put_user(len, optlen);
923 }
924#endif
925 return err;
926}
927
928#ifdef CONFIG_COMPAT
929int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
930 char __user *optval, int __user *optlen)
931{
932 int err;
933
934 if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
935 if (udp_prot.compat_getsockopt != NULL)
936 return udp_prot.compat_getsockopt(sk, level, optname,
937 optval, optlen);
938 return udp_prot.getsockopt(sk, level, optname, optval, optlen);
939 }
940
941 if (level != SOL_IPV6)
942 return -ENOPROTOOPT;
943
944 err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
945#ifdef CONFIG_NETFILTER
946 /* we need to exclude all possible EINVALs except default case */
947 if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM &&
948 optname != MCAST_MSFILTER) {
949 int len;
950
951 if (get_user(len, optlen))
952 return -EFAULT;
953
954 lock_sock(sk);
955 err = compat_nf_getsockopt(sk, PF_INET6,
956 optname, optval, &len);
957 release_sock(sk);
958 if (err >= 0)
959 err = put_user(len, optlen);
960 }
961#endif
962 return err;
963}
964
965EXPORT_SYMBOL(compat_ipv6_getsockopt);
966#endif
967
865void __init ipv6_packet_init(void) 968void __init ipv6_packet_init(void)
866{ 969{
867 dev_add_pack(&ipv6_packet_type); 970 dev_add_pack(&ipv6_packet_type);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 807c021d64a2..6e871afbb2c7 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -767,10 +767,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
767 * for deleted items allows change reports to use common code with 767 * for deleted items allows change reports to use common code with
768 * non-deleted or query-response MCA's. 768 * non-deleted or query-response MCA's.
769 */ 769 */
770 pmc = kmalloc(sizeof(*pmc), GFP_ATOMIC); 770 pmc = kzalloc(sizeof(*pmc), GFP_ATOMIC);
771 if (!pmc) 771 if (!pmc)
772 return; 772 return;
773 memset(pmc, 0, sizeof(*pmc)); 773
774 spin_lock_bh(&im->mca_lock); 774 spin_lock_bh(&im->mca_lock);
775 spin_lock_init(&pmc->mca_lock); 775 spin_lock_init(&pmc->mca_lock);
776 pmc->idev = im->idev; 776 pmc->idev = im->idev;
@@ -893,7 +893,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
893 * not found: create a new one. 893 * not found: create a new one.
894 */ 894 */
895 895
896 mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); 896 mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
897 897
898 if (mc == NULL) { 898 if (mc == NULL) {
899 write_unlock_bh(&idev->lock); 899 write_unlock_bh(&idev->lock);
@@ -901,7 +901,6 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
901 return -ENOMEM; 901 return -ENOMEM;
902 } 902 }
903 903
904 memset(mc, 0, sizeof(struct ifmcaddr6));
905 init_timer(&mc->mca_timer); 904 init_timer(&mc->mca_timer);
906 mc->mca_timer.function = igmp6_timer_handler; 905 mc->mca_timer.function = igmp6_timer_handler;
907 mc->mca_timer.data = (unsigned long) mc; 906 mc->mca_timer.data = (unsigned long) mc;
@@ -1934,10 +1933,10 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,
1934 psf_prev = psf; 1933 psf_prev = psf;
1935 } 1934 }
1936 if (!psf) { 1935 if (!psf) {
1937 psf = kmalloc(sizeof(*psf), GFP_ATOMIC); 1936 psf = kzalloc(sizeof(*psf), GFP_ATOMIC);
1938 if (!psf) 1937 if (!psf)
1939 return -ENOBUFS; 1938 return -ENOBUFS;
1940 memset(psf, 0, sizeof(*psf)); 1939
1941 psf->sf_addr = *psfsrc; 1940 psf->sf_addr = *psfsrc;
1942 if (psf_prev) { 1941 if (psf_prev) {
1943 psf_prev->sf_next = psf; 1942 psf_prev->sf_next = psf;
@@ -2431,7 +2430,7 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
2431{ 2430{
2432 struct seq_file *seq; 2431 struct seq_file *seq;
2433 int rc = -ENOMEM; 2432 int rc = -ENOMEM;
2434 struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); 2433 struct igmp6_mc_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
2435 2434
2436 if (!s) 2435 if (!s)
2437 goto out; 2436 goto out;
@@ -2442,7 +2441,6 @@ static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
2442 2441
2443 seq = file->private_data; 2442 seq = file->private_data;
2444 seq->private = s; 2443 seq->private = s;
2445 memset(s, 0, sizeof(*s));
2446out: 2444out:
2447 return rc; 2445 return rc;
2448out_kfree: 2446out_kfree:
@@ -2606,7 +2604,7 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
2606{ 2604{
2607 struct seq_file *seq; 2605 struct seq_file *seq;
2608 int rc = -ENOMEM; 2606 int rc = -ENOMEM;
2609 struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); 2607 struct igmp6_mcf_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
2610 2608
2611 if (!s) 2609 if (!s)
2612 goto out; 2610 goto out;
@@ -2617,7 +2615,6 @@ static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
2617 2615
2618 seq = file->private_data; 2616 seq = file->private_data;
2619 seq->private = s; 2617 seq->private = s;
2620 memset(s, 0, sizeof(*s));
2621out: 2618out:
2622 return rc; 2619 return rc;
2623out_kfree: 2620out_kfree:
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index cb8856b1d951..dfa20d3be9b6 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -156,7 +156,11 @@ struct neigh_table nd_tbl = {
156 156
157/* ND options */ 157/* ND options */
158struct ndisc_options { 158struct ndisc_options {
159 struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX]; 159 struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
160#ifdef CONFIG_IPV6_ROUTE_INFO
161 struct nd_opt_hdr *nd_opts_ri;
162 struct nd_opt_hdr *nd_opts_ri_end;
163#endif
160}; 164};
161 165
162#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] 166#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
@@ -255,6 +259,13 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
255 if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) 259 if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
256 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; 260 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
257 break; 261 break;
262#ifdef CONFIG_IPV6_ROUTE_INFO
263 case ND_OPT_ROUTE_INFO:
264 ndopts->nd_opts_ri_end = nd_opt;
265 if (!ndopts->nd_opts_ri)
266 ndopts->nd_opts_ri = nd_opt;
267 break;
268#endif
258 default: 269 default:
259 /* 270 /*
260 * Unknown options must be silently ignored, 271 * Unknown options must be silently ignored,
@@ -1019,10 +1030,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1019 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; 1030 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
1020 struct neighbour *neigh = NULL; 1031 struct neighbour *neigh = NULL;
1021 struct inet6_dev *in6_dev; 1032 struct inet6_dev *in6_dev;
1022 struct rt6_info *rt; 1033 struct rt6_info *rt = NULL;
1023 int lifetime; 1034 int lifetime;
1024 struct ndisc_options ndopts; 1035 struct ndisc_options ndopts;
1025 int optlen; 1036 int optlen;
1037 unsigned int pref = 0;
1026 1038
1027 __u8 * opt = (__u8 *)(ra_msg + 1); 1039 __u8 * opt = (__u8 *)(ra_msg + 1);
1028 1040
@@ -1081,8 +1093,19 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1081 (ra_msg->icmph.icmp6_addrconf_other ? 1093 (ra_msg->icmph.icmp6_addrconf_other ?
1082 IF_RA_OTHERCONF : 0); 1094 IF_RA_OTHERCONF : 0);
1083 1095
1096 if (!in6_dev->cnf.accept_ra_defrtr)
1097 goto skip_defrtr;
1098
1084 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); 1099 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1085 1100
1101#ifdef CONFIG_IPV6_ROUTER_PREF
1102 pref = ra_msg->icmph.icmp6_router_pref;
1103 /* 10b is handled as if it were 00b (medium) */
1104 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
1105 in6_dev->cnf.accept_ra_rtr_pref)
1106 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1107#endif
1108
1086 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); 1109 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
1087 1110
1088 if (rt) 1111 if (rt)
@@ -1098,7 +1121,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1098 ND_PRINTK3(KERN_DEBUG 1121 ND_PRINTK3(KERN_DEBUG
1099 "ICMPv6 RA: adding default router.\n"); 1122 "ICMPv6 RA: adding default router.\n");
1100 1123
1101 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); 1124 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
1102 if (rt == NULL) { 1125 if (rt == NULL) {
1103 ND_PRINTK0(KERN_ERR 1126 ND_PRINTK0(KERN_ERR
1104 "ICMPv6 RA: %s() failed to add default route.\n", 1127 "ICMPv6 RA: %s() failed to add default route.\n",
@@ -1117,6 +1140,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1117 return; 1140 return;
1118 } 1141 }
1119 neigh->flags |= NTF_ROUTER; 1142 neigh->flags |= NTF_ROUTER;
1143 } else if (rt) {
1144 rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
1120 } 1145 }
1121 1146
1122 if (rt) 1147 if (rt)
@@ -1128,6 +1153,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1128 rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; 1153 rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
1129 } 1154 }
1130 1155
1156skip_defrtr:
1157
1131 /* 1158 /*
1132 * Update Reachable Time and Retrans Timer 1159 * Update Reachable Time and Retrans Timer
1133 */ 1160 */
@@ -1186,7 +1213,21 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1186 NEIGH_UPDATE_F_ISROUTER); 1213 NEIGH_UPDATE_F_ISROUTER);
1187 } 1214 }
1188 1215
1189 if (ndopts.nd_opts_pi) { 1216#ifdef CONFIG_IPV6_ROUTE_INFO
1217 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
1218 struct nd_opt_hdr *p;
1219 for (p = ndopts.nd_opts_ri;
1220 p;
1221 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
1222 if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
1223 continue;
1224 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
1225 &skb->nh.ipv6h->saddr);
1226 }
1227 }
1228#endif
1229
1230 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
1190 struct nd_opt_hdr *p; 1231 struct nd_opt_hdr *p;
1191 for (p = ndopts.nd_opts_pi; 1232 for (p = ndopts.nd_opts_pi;
1192 p; 1233 p;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 2d6f8ecbc27b..98f78759f1ab 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -133,16 +133,6 @@ config IP6_NF_MATCH_EUI64
133 133
134 To compile it as a module, choose M here. If unsure, say N. 134 To compile it as a module, choose M here. If unsure, say N.
135 135
136config IP6_NF_MATCH_POLICY
137 tristate "IPsec policy match support"
138 depends on IP6_NF_IPTABLES && XFRM
139 help
140 Policy matching allows you to match packets based on the
141 IPsec policy that was used during decapsulation/will
142 be used during encapsulation.
143
144 To compile it as a module, choose M here. If unsure, say N.
145
146# The targets 136# The targets
147config IP6_NF_FILTER 137config IP6_NF_FILTER
148 tristate "Packet filtering" 138 tristate "Packet filtering"
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index db6073c94163..8436a1a1731f 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -9,7 +9,6 @@ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
9obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o 9obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
10obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o 10obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
11obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o 11obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
12obj-$(CONFIG_IP6_NF_MATCH_POLICY) += ip6t_policy.o
13obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o 12obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
14obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o 13obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
15obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o 14obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index af0635084df8..344eab3b5da8 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -35,6 +35,7 @@
35#include <linux/spinlock.h> 35#include <linux/spinlock.h>
36#include <linux/sysctl.h> 36#include <linux/sysctl.h>
37#include <linux/proc_fs.h> 37#include <linux/proc_fs.h>
38#include <linux/mutex.h>
38#include <net/sock.h> 39#include <net/sock.h>
39#include <net/ipv6.h> 40#include <net/ipv6.h>
40#include <net/ip6_route.h> 41#include <net/ip6_route.h>
@@ -65,7 +66,7 @@ static unsigned int queue_dropped = 0;
65static unsigned int queue_user_dropped = 0; 66static unsigned int queue_user_dropped = 0;
66static struct sock *ipqnl; 67static struct sock *ipqnl;
67static LIST_HEAD(queue_list); 68static LIST_HEAD(queue_list);
68static DECLARE_MUTEX(ipqnl_sem); 69static DEFINE_MUTEX(ipqnl_mutex);
69 70
70static void 71static void
71ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) 72ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict)
@@ -537,7 +538,7 @@ ipq_rcv_sk(struct sock *sk, int len)
537 struct sk_buff *skb; 538 struct sk_buff *skb;
538 unsigned int qlen; 539 unsigned int qlen;
539 540
540 down(&ipqnl_sem); 541 mutex_lock(&ipqnl_mutex);
541 542
542 for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { 543 for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) {
543 skb = skb_dequeue(&sk->sk_receive_queue); 544 skb = skb_dequeue(&sk->sk_receive_queue);
@@ -545,7 +546,7 @@ ipq_rcv_sk(struct sock *sk, int len)
545 kfree_skb(skb); 546 kfree_skb(skb);
546 } 547 }
547 548
548 up(&ipqnl_sem); 549 mutex_unlock(&ipqnl_mutex);
549} 550}
550 551
551static int 552static int
@@ -704,8 +705,8 @@ cleanup_sysctl:
704 705
705cleanup_ipqnl: 706cleanup_ipqnl:
706 sock_release(ipqnl->sk_socket); 707 sock_release(ipqnl->sk_socket);
707 down(&ipqnl_sem); 708 mutex_lock(&ipqnl_mutex);
708 up(&ipqnl_sem); 709 mutex_unlock(&ipqnl_mutex);
709 710
710cleanup_netlink_notifier: 711cleanup_netlink_notifier:
711 netlink_unregister_notifier(&ipq_nl_notifier); 712 netlink_unregister_notifier(&ipq_nl_notifier);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 74ff56c322f4..5a2063bda676 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -29,7 +29,7 @@
29#include <linux/icmpv6.h> 29#include <linux/icmpv6.h>
30#include <net/ipv6.h> 30#include <net/ipv6.h>
31#include <asm/uaccess.h> 31#include <asm/uaccess.h>
32#include <asm/semaphore.h> 32#include <linux/mutex.h>
33#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
34#include <linux/cpumask.h> 34#include <linux/cpumask.h>
35 35
@@ -94,19 +94,6 @@ do { \
94#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) 94#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
95#endif 95#endif
96 96
97int
98ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask,
99 const struct in6_addr *addr2)
100{
101 int i;
102 for( i = 0; i < 16; i++){
103 if((addr1->s6_addr[i] & mask->s6_addr[i]) !=
104 (addr2->s6_addr[i] & mask->s6_addr[i]))
105 return 1;
106 }
107 return 0;
108}
109
110/* Check for an extension */ 97/* Check for an extension */
111int 98int
112ip6t_ext_hdr(u8 nexthdr) 99ip6t_ext_hdr(u8 nexthdr)
@@ -135,10 +122,10 @@ ip6_packet_match(const struct sk_buff *skb,
135 122
136#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) 123#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
137 124
138 if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk, 125 if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
139 &ip6info->src), IP6T_INV_SRCIP) 126 &ip6info->src), IP6T_INV_SRCIP)
140 || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk, 127 || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
141 &ip6info->dst), IP6T_INV_DSTIP)) { 128 &ip6info->dst), IP6T_INV_DSTIP)) {
142 dprintf("Source or dest mismatch.\n"); 129 dprintf("Source or dest mismatch.\n");
143/* 130/*
144 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, 131 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
@@ -232,6 +219,7 @@ ip6t_error(struct sk_buff **pskb,
232 const struct net_device *in, 219 const struct net_device *in,
233 const struct net_device *out, 220 const struct net_device *out,
234 unsigned int hooknum, 221 unsigned int hooknum,
222 const struct xt_target *target,
235 const void *targinfo, 223 const void *targinfo,
236 void *userinfo) 224 void *userinfo)
237{ 225{
@@ -251,7 +239,7 @@ int do_match(struct ip6t_entry_match *m,
251 int *hotdrop) 239 int *hotdrop)
252{ 240{
253 /* Stop iteration if it doesn't match */ 241 /* Stop iteration if it doesn't match */
254 if (!m->u.kernel.match->match(skb, in, out, m->data, 242 if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
255 offset, protoff, hotdrop)) 243 offset, protoff, hotdrop))
256 return 1; 244 return 1;
257 else 245 else
@@ -373,6 +361,7 @@ ip6t_do_table(struct sk_buff **pskb,
373 verdict = t->u.kernel.target->target(pskb, 361 verdict = t->u.kernel.target->target(pskb,
374 in, out, 362 in, out,
375 hook, 363 hook,
364 t->u.kernel.target,
376 t->data, 365 t->data,
377 userdata); 366 userdata);
378 367
@@ -531,7 +520,7 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
531 return 1; 520 return 1;
532 521
533 if (m->u.kernel.match->destroy) 522 if (m->u.kernel.match->destroy)
534 m->u.kernel.match->destroy(m->data, 523 m->u.kernel.match->destroy(m->u.kernel.match, m->data,
535 m->u.match_size - sizeof(*m)); 524 m->u.match_size - sizeof(*m));
536 module_put(m->u.kernel.match->me); 525 module_put(m->u.kernel.match->me);
537 return 0; 526 return 0;
@@ -544,21 +533,12 @@ standard_check(const struct ip6t_entry_target *t,
544 struct ip6t_standard_target *targ = (void *)t; 533 struct ip6t_standard_target *targ = (void *)t;
545 534
546 /* Check standard info. */ 535 /* Check standard info. */
547 if (t->u.target_size
548 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
549 duprintf("standard_check: target size %u != %u\n",
550 t->u.target_size,
551 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
552 return 0;
553 }
554
555 if (targ->verdict >= 0 536 if (targ->verdict >= 0
556 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) { 537 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
557 duprintf("ip6t_standard_check: bad verdict (%i)\n", 538 duprintf("ip6t_standard_check: bad verdict (%i)\n",
558 targ->verdict); 539 targ->verdict);
559 return 0; 540 return 0;
560 } 541 }
561
562 if (targ->verdict < -NF_MAX_VERDICT - 1) { 542 if (targ->verdict < -NF_MAX_VERDICT - 1) {
563 duprintf("ip6t_standard_check: bad negative verdict (%i)\n", 543 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
564 targ->verdict); 544 targ->verdict);
@@ -575,6 +555,7 @@ check_match(struct ip6t_entry_match *m,
575 unsigned int *i) 555 unsigned int *i)
576{ 556{
577 struct ip6t_match *match; 557 struct ip6t_match *match;
558 int ret;
578 559
579 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name, 560 match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
580 m->u.user.revision), 561 m->u.user.revision),
@@ -585,18 +566,27 @@ check_match(struct ip6t_entry_match *m,
585 } 566 }
586 m->u.kernel.match = match; 567 m->u.kernel.match = match;
587 568
569 ret = xt_check_match(match, AF_INET6, m->u.match_size - sizeof(*m),
570 name, hookmask, ipv6->proto,
571 ipv6->invflags & IP6T_INV_PROTO);
572 if (ret)
573 goto err;
574
588 if (m->u.kernel.match->checkentry 575 if (m->u.kernel.match->checkentry
589 && !m->u.kernel.match->checkentry(name, ipv6, m->data, 576 && !m->u.kernel.match->checkentry(name, ipv6, match, m->data,
590 m->u.match_size - sizeof(*m), 577 m->u.match_size - sizeof(*m),
591 hookmask)) { 578 hookmask)) {
592 module_put(m->u.kernel.match->me);
593 duprintf("ip_tables: check failed for `%s'.\n", 579 duprintf("ip_tables: check failed for `%s'.\n",
594 m->u.kernel.match->name); 580 m->u.kernel.match->name);
595 return -EINVAL; 581 ret = -EINVAL;
582 goto err;
596 } 583 }
597 584
598 (*i)++; 585 (*i)++;
599 return 0; 586 return 0;
587err:
588 module_put(m->u.kernel.match->me);
589 return ret;
600} 590}
601 591
602static struct ip6t_target ip6t_standard_target; 592static struct ip6t_target ip6t_standard_target;
@@ -632,26 +622,32 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
632 } 622 }
633 t->u.kernel.target = target; 623 t->u.kernel.target = target;
634 624
625 ret = xt_check_target(target, AF_INET6, t->u.target_size - sizeof(*t),
626 name, e->comefrom, e->ipv6.proto,
627 e->ipv6.invflags & IP6T_INV_PROTO);
628 if (ret)
629 goto err;
630
635 if (t->u.kernel.target == &ip6t_standard_target) { 631 if (t->u.kernel.target == &ip6t_standard_target) {
636 if (!standard_check(t, size)) { 632 if (!standard_check(t, size)) {
637 ret = -EINVAL; 633 ret = -EINVAL;
638 goto cleanup_matches; 634 goto cleanup_matches;
639 } 635 }
640 } else if (t->u.kernel.target->checkentry 636 } else if (t->u.kernel.target->checkentry
641 && !t->u.kernel.target->checkentry(name, e, t->data, 637 && !t->u.kernel.target->checkentry(name, e, target, t->data,
642 t->u.target_size 638 t->u.target_size
643 - sizeof(*t), 639 - sizeof(*t),
644 e->comefrom)) { 640 e->comefrom)) {
645 module_put(t->u.kernel.target->me);
646 duprintf("ip_tables: check failed for `%s'.\n", 641 duprintf("ip_tables: check failed for `%s'.\n",
647 t->u.kernel.target->name); 642 t->u.kernel.target->name);
648 ret = -EINVAL; 643 ret = -EINVAL;
649 goto cleanup_matches; 644 goto err;
650 } 645 }
651 646
652 (*i)++; 647 (*i)++;
653 return 0; 648 return 0;
654 649 err:
650 module_put(t->u.kernel.target->me);
655 cleanup_matches: 651 cleanup_matches:
656 IP6T_MATCH_ITERATE(e, cleanup_match, &j); 652 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
657 return ret; 653 return ret;
@@ -712,7 +708,7 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i)
712 IP6T_MATCH_ITERATE(e, cleanup_match, NULL); 708 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
713 t = ip6t_get_target(e); 709 t = ip6t_get_target(e);
714 if (t->u.kernel.target->destroy) 710 if (t->u.kernel.target->destroy)
715 t->u.kernel.target->destroy(t->data, 711 t->u.kernel.target->destroy(t->u.kernel.target, t->data,
716 t->u.target_size - sizeof(*t)); 712 t->u.target_size - sizeof(*t));
717 module_put(t->u.kernel.target->me); 713 module_put(t->u.kernel.target->me);
718 return 0; 714 return 0;
@@ -1333,6 +1329,7 @@ static int
1333icmp6_match(const struct sk_buff *skb, 1329icmp6_match(const struct sk_buff *skb,
1334 const struct net_device *in, 1330 const struct net_device *in,
1335 const struct net_device *out, 1331 const struct net_device *out,
1332 const struct xt_match *match,
1336 const void *matchinfo, 1333 const void *matchinfo,
1337 int offset, 1334 int offset,
1338 unsigned int protoff, 1335 unsigned int protoff,
@@ -1365,28 +1362,27 @@ icmp6_match(const struct sk_buff *skb,
1365static int 1362static int
1366icmp6_checkentry(const char *tablename, 1363icmp6_checkentry(const char *tablename,
1367 const void *entry, 1364 const void *entry,
1365 const struct xt_match *match,
1368 void *matchinfo, 1366 void *matchinfo,
1369 unsigned int matchsize, 1367 unsigned int matchsize,
1370 unsigned int hook_mask) 1368 unsigned int hook_mask)
1371{ 1369{
1372 const struct ip6t_ip6 *ipv6 = entry;
1373 const struct ip6t_icmp *icmpinfo = matchinfo; 1370 const struct ip6t_icmp *icmpinfo = matchinfo;
1374 1371
1375 /* Must specify proto == ICMP, and no unknown invflags */ 1372 /* Must specify no unknown invflags */
1376 return ipv6->proto == IPPROTO_ICMPV6 1373 return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1377 && !(ipv6->invflags & IP6T_INV_PROTO)
1378 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1379 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1380} 1374}
1381 1375
1382/* The built-in targets: standard (NULL) and error. */ 1376/* The built-in targets: standard (NULL) and error. */
1383static struct ip6t_target ip6t_standard_target = { 1377static struct ip6t_target ip6t_standard_target = {
1384 .name = IP6T_STANDARD_TARGET, 1378 .name = IP6T_STANDARD_TARGET,
1379 .targetsize = sizeof(int),
1385}; 1380};
1386 1381
1387static struct ip6t_target ip6t_error_target = { 1382static struct ip6t_target ip6t_error_target = {
1388 .name = IP6T_ERROR_TARGET, 1383 .name = IP6T_ERROR_TARGET,
1389 .target = ip6t_error, 1384 .target = ip6t_error,
1385 .targetsize = IP6T_FUNCTION_MAXNAMELEN,
1390}; 1386};
1391 1387
1392static struct nf_sockopt_ops ip6t_sockopts = { 1388static struct nf_sockopt_ops ip6t_sockopts = {
@@ -1402,7 +1398,9 @@ static struct nf_sockopt_ops ip6t_sockopts = {
1402static struct ip6t_match icmp6_matchstruct = { 1398static struct ip6t_match icmp6_matchstruct = {
1403 .name = "icmp6", 1399 .name = "icmp6",
1404 .match = &icmp6_match, 1400 .match = &icmp6_match,
1405 .checkentry = &icmp6_checkentry, 1401 .matchsize = sizeof(struct ip6t_icmp),
1402 .checkentry = icmp6_checkentry,
1403 .proto = IPPROTO_ICMPV6,
1406}; 1404};
1407 1405
1408static int __init init(void) 1406static int __init init(void)
@@ -1515,7 +1513,6 @@ EXPORT_SYMBOL(ip6t_unregister_table);
1515EXPORT_SYMBOL(ip6t_do_table); 1513EXPORT_SYMBOL(ip6t_do_table);
1516EXPORT_SYMBOL(ip6t_ext_hdr); 1514EXPORT_SYMBOL(ip6t_ext_hdr);
1517EXPORT_SYMBOL(ipv6_find_hdr); 1515EXPORT_SYMBOL(ipv6_find_hdr);
1518EXPORT_SYMBOL(ip6_masked_addrcmp);
1519 1516
1520module_init(init); 1517module_init(init);
1521module_exit(fini); 1518module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index 306200c35057..da14c6d86bcc 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -21,6 +21,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
21 const struct net_device *in, 21 const struct net_device *in,
22 const struct net_device *out, 22 const struct net_device *out,
23 unsigned int hooknum, 23 unsigned int hooknum,
24 const struct xt_target *target,
24 const void *targinfo, void *userinfo) 25 const void *targinfo, void *userinfo)
25{ 26{
26 struct ipv6hdr *ip6h; 27 struct ipv6hdr *ip6h;
@@ -63,43 +64,31 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
63 64
64static int ip6t_hl_checkentry(const char *tablename, 65static int ip6t_hl_checkentry(const char *tablename,
65 const void *entry, 66 const void *entry,
67 const struct xt_target *target,
66 void *targinfo, 68 void *targinfo,
67 unsigned int targinfosize, 69 unsigned int targinfosize,
68 unsigned int hook_mask) 70 unsigned int hook_mask)
69{ 71{
70 struct ip6t_HL_info *info = targinfo; 72 struct ip6t_HL_info *info = targinfo;
71 73
72 if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
73 printk(KERN_WARNING "ip6t_HL: targinfosize %u != %Zu\n",
74 targinfosize,
75 IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
76 return 0;
77 }
78
79 if (strcmp(tablename, "mangle")) {
80 printk(KERN_WARNING "ip6t_HL: can only be called from "
81 "\"mangle\" table, not \"%s\"\n", tablename);
82 return 0;
83 }
84
85 if (info->mode > IP6T_HL_MAXMODE) { 74 if (info->mode > IP6T_HL_MAXMODE) {
86 printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", 75 printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
87 info->mode); 76 info->mode);
88 return 0; 77 return 0;
89 } 78 }
90
91 if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { 79 if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
92 printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " 80 printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
93 "make sense with value 0\n"); 81 "make sense with value 0\n");
94 return 0; 82 return 0;
95 } 83 }
96
97 return 1; 84 return 1;
98} 85}
99 86
100static struct ip6t_target ip6t_HL = { 87static struct ip6t_target ip6t_HL = {
101 .name = "HL", 88 .name = "HL",
102 .target = ip6t_hl_target, 89 .target = ip6t_hl_target,
90 .targetsize = sizeof(struct ip6t_HL_info),
91 .table = "mangle",
103 .checkentry = ip6t_hl_checkentry, 92 .checkentry = ip6t_hl_checkentry,
104 .me = THIS_MODULE 93 .me = THIS_MODULE
105}; 94};
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 6b930efa9fb9..07c6bcbe4c5f 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -426,6 +426,7 @@ ip6t_log_target(struct sk_buff **pskb,
426 const struct net_device *in, 426 const struct net_device *in,
427 const struct net_device *out, 427 const struct net_device *out,
428 unsigned int hooknum, 428 unsigned int hooknum,
429 const struct xt_target *target,
429 const void *targinfo, 430 const void *targinfo,
430 void *userinfo) 431 void *userinfo)
431{ 432{
@@ -449,35 +450,29 @@ ip6t_log_target(struct sk_buff **pskb,
449 450
450static int ip6t_log_checkentry(const char *tablename, 451static int ip6t_log_checkentry(const char *tablename,
451 const void *entry, 452 const void *entry,
453 const struct xt_target *target,
452 void *targinfo, 454 void *targinfo,
453 unsigned int targinfosize, 455 unsigned int targinfosize,
454 unsigned int hook_mask) 456 unsigned int hook_mask)
455{ 457{
456 const struct ip6t_log_info *loginfo = targinfo; 458 const struct ip6t_log_info *loginfo = targinfo;
457 459
458 if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_log_info))) {
459 DEBUGP("LOG: targinfosize %u != %u\n",
460 targinfosize, IP6T_ALIGN(sizeof(struct ip6t_log_info)));
461 return 0;
462 }
463
464 if (loginfo->level >= 8) { 460 if (loginfo->level >= 8) {
465 DEBUGP("LOG: level %u >= 8\n", loginfo->level); 461 DEBUGP("LOG: level %u >= 8\n", loginfo->level);
466 return 0; 462 return 0;
467 } 463 }
468
469 if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') { 464 if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
470 DEBUGP("LOG: prefix term %i\n", 465 DEBUGP("LOG: prefix term %i\n",
471 loginfo->prefix[sizeof(loginfo->prefix)-1]); 466 loginfo->prefix[sizeof(loginfo->prefix)-1]);
472 return 0; 467 return 0;
473 } 468 }
474
475 return 1; 469 return 1;
476} 470}
477 471
478static struct ip6t_target ip6t_log_reg = { 472static struct ip6t_target ip6t_log_reg = {
479 .name = "LOG", 473 .name = "LOG",
480 .target = ip6t_log_target, 474 .target = ip6t_log_target,
475 .targetsize = sizeof(struct ip6t_log_info),
481 .checkentry = ip6t_log_checkentry, 476 .checkentry = ip6t_log_checkentry,
482 .me = THIS_MODULE, 477 .me = THIS_MODULE,
483}; 478};
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index 0e6d1d4bbd5c..ddfa38575fe2 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -179,6 +179,7 @@ static unsigned int reject6_target(struct sk_buff **pskb,
179 const struct net_device *in, 179 const struct net_device *in,
180 const struct net_device *out, 180 const struct net_device *out,
181 unsigned int hooknum, 181 unsigned int hooknum,
182 const struct xt_target *target,
182 const void *targinfo, 183 const void *targinfo,
183 void *userinfo) 184 void *userinfo)
184{ 185{
@@ -221,6 +222,7 @@ static unsigned int reject6_target(struct sk_buff **pskb,
221 222
222static int check(const char *tablename, 223static int check(const char *tablename,
223 const void *entry, 224 const void *entry,
225 const struct xt_target *target,
224 void *targinfo, 226 void *targinfo,
225 unsigned int targinfosize, 227 unsigned int targinfosize,
226 unsigned int hook_mask) 228 unsigned int hook_mask)
@@ -228,24 +230,6 @@ static int check(const char *tablename,
228 const struct ip6t_reject_info *rejinfo = targinfo; 230 const struct ip6t_reject_info *rejinfo = targinfo;
229 const struct ip6t_entry *e = entry; 231 const struct ip6t_entry *e = entry;
230 232
231 if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
232 DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
233 return 0;
234 }
235
236 /* Only allow these for packet filtering. */
237 if (strcmp(tablename, "filter") != 0) {
238 DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
239 return 0;
240 }
241
242 if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
243 | (1 << NF_IP6_FORWARD)
244 | (1 << NF_IP6_LOCAL_OUT))) != 0) {
245 DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
246 return 0;
247 }
248
249 if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { 233 if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
250 printk("ip6t_REJECT: ECHOREPLY is not supported.\n"); 234 printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
251 return 0; 235 return 0;
@@ -257,13 +241,16 @@ static int check(const char *tablename,
257 return 0; 241 return 0;
258 } 242 }
259 } 243 }
260
261 return 1; 244 return 1;
262} 245}
263 246
264static struct ip6t_target ip6t_reject_reg = { 247static struct ip6t_target ip6t_reject_reg = {
265 .name = "REJECT", 248 .name = "REJECT",
266 .target = reject6_target, 249 .target = reject6_target,
250 .targetsize = sizeof(struct ip6t_reject_info),
251 .table = "filter",
252 .hooks = (1 << NF_IP6_LOCAL_IN) | (1 << NF_IP6_FORWARD) |
253 (1 << NF_IP6_LOCAL_OUT),
267 .checkentry = check, 254 .checkentry = check,
268 .me = THIS_MODULE 255 .me = THIS_MODULE
269}; 256};
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index 219a30365dff..178f6fb1e53d 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -44,6 +44,7 @@ static int
44match(const struct sk_buff *skb, 44match(const struct sk_buff *skb,
45 const struct net_device *in, 45 const struct net_device *in,
46 const struct net_device *out, 46 const struct net_device *out,
47 const struct xt_match *match,
47 const void *matchinfo, 48 const void *matchinfo,
48 int offset, 49 int offset,
49 unsigned int protoff, 50 unsigned int protoff,
@@ -99,17 +100,13 @@ match(const struct sk_buff *skb,
99static int 100static int
100checkentry(const char *tablename, 101checkentry(const char *tablename,
101 const void *entry, 102 const void *entry,
103 const struct xt_match *match,
102 void *matchinfo, 104 void *matchinfo,
103 unsigned int matchinfosize, 105 unsigned int matchinfosize,
104 unsigned int hook_mask) 106 unsigned int hook_mask)
105{ 107{
106 const struct ip6t_ah *ahinfo = matchinfo; 108 const struct ip6t_ah *ahinfo = matchinfo;
107 109
108 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
109 DEBUGP("ip6t_ah: matchsize %u != %u\n",
110 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
111 return 0;
112 }
113 if (ahinfo->invflags & ~IP6T_AH_INV_MASK) { 110 if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
114 DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags); 111 DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
115 return 0; 112 return 0;
@@ -119,8 +116,9 @@ checkentry(const char *tablename,
119 116
120static struct ip6t_match ah_match = { 117static struct ip6t_match ah_match = {
121 .name = "ah", 118 .name = "ah",
122 .match = &match, 119 .match = match,
123 .checkentry = &checkentry, 120 .matchsize = sizeof(struct ip6t_ah),
121 .checkentry = checkentry,
124 .me = THIS_MODULE, 122 .me = THIS_MODULE,
125}; 123};
126 124
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c
index b4c153a53500..e97a70226987 100644
--- a/net/ipv6/netfilter/ip6t_dst.c
+++ b/net/ipv6/netfilter/ip6t_dst.c
@@ -55,6 +55,7 @@ static int
55match(const struct sk_buff *skb, 55match(const struct sk_buff *skb,
56 const struct net_device *in, 56 const struct net_device *in,
57 const struct net_device *out, 57 const struct net_device *out,
58 const struct xt_match *match,
58 const void *matchinfo, 59 const void *matchinfo,
59 int offset, 60 int offset,
60 unsigned int protoff, 61 unsigned int protoff,
@@ -179,22 +180,17 @@ match(const struct sk_buff *skb,
179static int 180static int
180checkentry(const char *tablename, 181checkentry(const char *tablename,
181 const void *info, 182 const void *info,
183 const struct xt_match *match,
182 void *matchinfo, 184 void *matchinfo,
183 unsigned int matchinfosize, 185 unsigned int matchinfosize,
184 unsigned int hook_mask) 186 unsigned int hook_mask)
185{ 187{
186 const struct ip6t_opts *optsinfo = matchinfo; 188 const struct ip6t_opts *optsinfo = matchinfo;
187 189
188 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
189 DEBUGP("ip6t_opts: matchsize %u != %u\n",
190 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
191 return 0;
192 }
193 if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { 190 if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
194 DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); 191 DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
195 return 0; 192 return 0;
196 } 193 }
197
198 return 1; 194 return 1;
199} 195}
200 196
@@ -204,8 +200,9 @@ static struct ip6t_match opts_match = {
204#else 200#else
205 .name = "dst", 201 .name = "dst",
206#endif 202#endif
207 .match = &match, 203 .match = match,
208 .checkentry = &checkentry, 204 .matchsize = sizeof(struct ip6t_opts),
205 .checkentry = checkentry,
209 .me = THIS_MODULE, 206 .me = THIS_MODULE,
210}; 207};
211 208
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
index 724285df8711..540b8bfd5055 100644
--- a/net/ipv6/netfilter/ip6t_esp.c
+++ b/net/ipv6/netfilter/ip6t_esp.c
@@ -44,6 +44,7 @@ static int
44match(const struct sk_buff *skb, 44match(const struct sk_buff *skb,
45 const struct net_device *in, 45 const struct net_device *in,
46 const struct net_device *out, 46 const struct net_device *out,
47 const struct xt_match *match,
47 const void *matchinfo, 48 const void *matchinfo,
48 int offset, 49 int offset,
49 unsigned int protoff, 50 unsigned int protoff,
@@ -77,17 +78,13 @@ match(const struct sk_buff *skb,
77static int 78static int
78checkentry(const char *tablename, 79checkentry(const char *tablename,
79 const void *ip, 80 const void *ip,
81 const struct xt_match *match,
80 void *matchinfo, 82 void *matchinfo,
81 unsigned int matchinfosize, 83 unsigned int matchinfosize,
82 unsigned int hook_mask) 84 unsigned int hook_mask)
83{ 85{
84 const struct ip6t_esp *espinfo = matchinfo; 86 const struct ip6t_esp *espinfo = matchinfo;
85 87
86 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) {
87 DEBUGP("ip6t_esp: matchsize %u != %u\n",
88 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp)));
89 return 0;
90 }
91 if (espinfo->invflags & ~IP6T_ESP_INV_MASK) { 88 if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
92 DEBUGP("ip6t_esp: unknown flags %X\n", 89 DEBUGP("ip6t_esp: unknown flags %X\n",
93 espinfo->invflags); 90 espinfo->invflags);
@@ -98,8 +95,9 @@ checkentry(const char *tablename,
98 95
99static struct ip6t_match esp_match = { 96static struct ip6t_match esp_match = {
100 .name = "esp", 97 .name = "esp",
101 .match = &match, 98 .match = match,
102 .checkentry = &checkentry, 99 .matchsize = sizeof(struct ip6t_esp),
100 .checkentry = checkentry,
103 .me = THIS_MODULE, 101 .me = THIS_MODULE,
104}; 102};
105 103
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 27396ac0b9ed..d4b0bad52830 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -22,6 +22,7 @@ static int
22match(const struct sk_buff *skb, 22match(const struct sk_buff *skb,
23 const struct net_device *in, 23 const struct net_device *in,
24 const struct net_device *out, 24 const struct net_device *out,
25 const struct xt_match *match,
25 const void *matchinfo, 26 const void *matchinfo,
26 int offset, 27 int offset,
27 unsigned int protoff, 28 unsigned int protoff,
@@ -60,30 +61,12 @@ match(const struct sk_buff *skb,
60 return 0; 61 return 0;
61} 62}
62 63
63static int
64ip6t_eui64_checkentry(const char *tablename,
65 const void *ip,
66 void *matchinfo,
67 unsigned int matchsize,
68 unsigned int hook_mask)
69{
70 if (hook_mask
71 & ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
72 (1 << NF_IP6_FORWARD))) {
73 printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
74 return 0;
75 }
76
77 if (matchsize != IP6T_ALIGN(sizeof(int)))
78 return 0;
79
80 return 1;
81}
82
83static struct ip6t_match eui64_match = { 64static struct ip6t_match eui64_match = {
84 .name = "eui64", 65 .name = "eui64",
85 .match = &match, 66 .match = match,
86 .checkentry = &ip6t_eui64_checkentry, 67 .matchsize = sizeof(int),
68 .hooks = (1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
69 (1 << NF_IP6_FORWARD),
87 .me = THIS_MODULE, 70 .me = THIS_MODULE,
88}; 71};
89 72
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index 4c14125a0e26..4c41e14823d5 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -43,6 +43,7 @@ static int
43match(const struct sk_buff *skb, 43match(const struct sk_buff *skb,
44 const struct net_device *in, 44 const struct net_device *in,
45 const struct net_device *out, 45 const struct net_device *out,
46 const struct xt_match *match,
46 const void *matchinfo, 47 const void *matchinfo,
47 int offset, 48 int offset,
48 unsigned int protoff, 49 unsigned int protoff,
@@ -116,29 +117,25 @@ match(const struct sk_buff *skb,
116static int 117static int
117checkentry(const char *tablename, 118checkentry(const char *tablename,
118 const void *ip, 119 const void *ip,
120 const struct xt_match *match,
119 void *matchinfo, 121 void *matchinfo,
120 unsigned int matchinfosize, 122 unsigned int matchinfosize,
121 unsigned int hook_mask) 123 unsigned int hook_mask)
122{ 124{
123 const struct ip6t_frag *fraginfo = matchinfo; 125 const struct ip6t_frag *fraginfo = matchinfo;
124 126
125 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
126 DEBUGP("ip6t_frag: matchsize %u != %u\n",
127 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
128 return 0;
129 }
130 if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { 127 if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
131 DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags); 128 DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
132 return 0; 129 return 0;
133 } 130 }
134
135 return 1; 131 return 1;
136} 132}
137 133
138static struct ip6t_match frag_match = { 134static struct ip6t_match frag_match = {
139 .name = "frag", 135 .name = "frag",
140 .match = &match, 136 .match = match,
141 .checkentry = &checkentry, 137 .matchsize = sizeof(struct ip6t_frag),
138 .checkentry = checkentry,
142 .me = THIS_MODULE, 139 .me = THIS_MODULE,
143}; 140};
144 141
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index 37a8474a7e0c..b4a1fdfe6abc 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -55,6 +55,7 @@ static int
55match(const struct sk_buff *skb, 55match(const struct sk_buff *skb,
56 const struct net_device *in, 56 const struct net_device *in,
57 const struct net_device *out, 57 const struct net_device *out,
58 const struct xt_match *match,
58 const void *matchinfo, 59 const void *matchinfo,
59 int offset, 60 int offset,
60 unsigned int protoff, 61 unsigned int protoff,
@@ -179,22 +180,17 @@ match(const struct sk_buff *skb,
179static int 180static int
180checkentry(const char *tablename, 181checkentry(const char *tablename,
181 const void *entry, 182 const void *entry,
183 const struct xt_match *match,
182 void *matchinfo, 184 void *matchinfo,
183 unsigned int matchinfosize, 185 unsigned int matchinfosize,
184 unsigned int hook_mask) 186 unsigned int hook_mask)
185{ 187{
186 const struct ip6t_opts *optsinfo = matchinfo; 188 const struct ip6t_opts *optsinfo = matchinfo;
187 189
188 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
189 DEBUGP("ip6t_opts: matchsize %u != %u\n",
190 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
191 return 0;
192 }
193 if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { 190 if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
194 DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags); 191 DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
195 return 0; 192 return 0;
196 } 193 }
197
198 return 1; 194 return 1;
199} 195}
200 196
@@ -204,8 +200,9 @@ static struct ip6t_match opts_match = {
204#else 200#else
205 .name = "dst", 201 .name = "dst",
206#endif 202#endif
207 .match = &match, 203 .match = match,
208 .checkentry = &checkentry, 204 .matchsize = sizeof(struct ip6t_opts),
205 .checkentry = checkentry,
209 .me = THIS_MODULE, 206 .me = THIS_MODULE,
210}; 207};
211 208
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index c5d9079f2d9d..374055733b26 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -18,10 +18,10 @@ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
18MODULE_DESCRIPTION("IP tables Hop Limit matching module"); 18MODULE_DESCRIPTION("IP tables Hop Limit matching module");
19MODULE_LICENSE("GPL"); 19MODULE_LICENSE("GPL");
20 20
21static int match(const struct sk_buff *skb, const struct net_device *in, 21static int match(const struct sk_buff *skb,
22 const struct net_device *out, const void *matchinfo, 22 const struct net_device *in, const struct net_device *out,
23 int offset, unsigned int protoff, 23 const struct xt_match *match, const void *matchinfo,
24 int *hotdrop) 24 int offset, unsigned int protoff, int *hotdrop)
25{ 25{
26 const struct ip6t_hl_info *info = matchinfo; 26 const struct ip6t_hl_info *info = matchinfo;
27 const struct ipv6hdr *ip6h = skb->nh.ipv6h; 27 const struct ipv6hdr *ip6h = skb->nh.ipv6h;
@@ -48,20 +48,10 @@ static int match(const struct sk_buff *skb, const struct net_device *in,
48 return 0; 48 return 0;
49} 49}
50 50
51static int checkentry(const char *tablename, const void *entry,
52 void *matchinfo, unsigned int matchsize,
53 unsigned int hook_mask)
54{
55 if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info)))
56 return 0;
57
58 return 1;
59}
60
61static struct ip6t_match hl_match = { 51static struct ip6t_match hl_match = {
62 .name = "hl", 52 .name = "hl",
63 .match = &match, 53 .match = match,
64 .checkentry = &checkentry, 54 .matchsize = sizeof(struct ip6t_hl_info),
65 .me = THIS_MODULE, 55 .me = THIS_MODULE,
66}; 56};
67 57
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index 83ad6b272f7e..9375eeb1369f 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -29,6 +29,7 @@ static int
29ipv6header_match(const struct sk_buff *skb, 29ipv6header_match(const struct sk_buff *skb,
30 const struct net_device *in, 30 const struct net_device *in,
31 const struct net_device *out, 31 const struct net_device *out,
32 const struct xt_match *match,
32 const void *matchinfo, 33 const void *matchinfo,
33 int offset, 34 int offset,
34 unsigned int protoff, 35 unsigned int protoff,
@@ -125,17 +126,13 @@ ipv6header_match(const struct sk_buff *skb,
125static int 126static int
126ipv6header_checkentry(const char *tablename, 127ipv6header_checkentry(const char *tablename,
127 const void *ip, 128 const void *ip,
129 const struct xt_match *match,
128 void *matchinfo, 130 void *matchinfo,
129 unsigned int matchsize, 131 unsigned int matchsize,
130 unsigned int hook_mask) 132 unsigned int hook_mask)
131{ 133{
132 const struct ip6t_ipv6header_info *info = matchinfo; 134 const struct ip6t_ipv6header_info *info = matchinfo;
133 135
134 /* Check for obvious errors */
135 /* This match is valid in all hooks! */
136 if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
137 return 0;
138
139 /* invflags is 0 or 0xff in hard mode */ 136 /* invflags is 0 or 0xff in hard mode */
140 if ((!info->modeflag) && info->invflags != 0x00 && 137 if ((!info->modeflag) && info->invflags != 0x00 &&
141 info->invflags != 0xFF) 138 info->invflags != 0xFF)
@@ -147,6 +144,7 @@ ipv6header_checkentry(const char *tablename,
147static struct ip6t_match ip6t_ipv6header_match = { 144static struct ip6t_match ip6t_ipv6header_match = {
148 .name = "ipv6header", 145 .name = "ipv6header",
149 .match = &ipv6header_match, 146 .match = &ipv6header_match,
147 .matchsize = sizeof(struct ip6t_ipv6header_info),
150 .checkentry = &ipv6header_checkentry, 148 .checkentry = &ipv6header_checkentry,
151 .destroy = NULL, 149 .destroy = NULL,
152 .me = THIS_MODULE, 150 .me = THIS_MODULE,
diff --git a/net/ipv6/netfilter/ip6t_multiport.c b/net/ipv6/netfilter/ip6t_multiport.c
index 49f7829dfbc2..752b65d21c72 100644
--- a/net/ipv6/netfilter/ip6t_multiport.c
+++ b/net/ipv6/netfilter/ip6t_multiport.c
@@ -51,6 +51,7 @@ static int
51match(const struct sk_buff *skb, 51match(const struct sk_buff *skb,
52 const struct net_device *in, 52 const struct net_device *in,
53 const struct net_device *out, 53 const struct net_device *out,
54 const struct xt_match *match,
54 const void *matchinfo, 55 const void *matchinfo,
55 int offset, 56 int offset,
56 unsigned int protoff, 57 unsigned int protoff,
@@ -85,6 +86,7 @@ match(const struct sk_buff *skb,
85static int 86static int
86checkentry(const char *tablename, 87checkentry(const char *tablename,
87 const void *info, 88 const void *info,
89 const struct xt_match *match,
88 void *matchinfo, 90 void *matchinfo,
89 unsigned int matchsize, 91 unsigned int matchsize,
90 unsigned int hook_mask) 92 unsigned int hook_mask)
@@ -92,13 +94,9 @@ checkentry(const char *tablename,
92 const struct ip6t_ip6 *ip = info; 94 const struct ip6t_ip6 *ip = info;
93 const struct ip6t_multiport *multiinfo = matchinfo; 95 const struct ip6t_multiport *multiinfo = matchinfo;
94 96
95 if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_multiport)))
96 return 0;
97
98 /* Must specify proto == TCP/UDP, no unknown flags or bad count */ 97 /* Must specify proto == TCP/UDP, no unknown flags or bad count */
99 return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) 98 return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
100 && !(ip->invflags & IP6T_INV_PROTO) 99 && !(ip->invflags & IP6T_INV_PROTO)
101 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_multiport))
102 && (multiinfo->flags == IP6T_MULTIPORT_SOURCE 100 && (multiinfo->flags == IP6T_MULTIPORT_SOURCE
103 || multiinfo->flags == IP6T_MULTIPORT_DESTINATION 101 || multiinfo->flags == IP6T_MULTIPORT_DESTINATION
104 || multiinfo->flags == IP6T_MULTIPORT_EITHER) 102 || multiinfo->flags == IP6T_MULTIPORT_EITHER)
@@ -107,8 +105,9 @@ checkentry(const char *tablename,
107 105
108static struct ip6t_match multiport_match = { 106static struct ip6t_match multiport_match = {
109 .name = "multiport", 107 .name = "multiport",
110 .match = &match, 108 .match = match,
111 .checkentry = &checkentry, 109 .matchsize = sizeof(struct ip6t_multiport),
110 .checkentry = checkentry,
112 .me = THIS_MODULE, 111 .me = THIS_MODULE,
113}; 112};
114 113
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
index 8c8a4c7ec934..e2cee3bcdef9 100644
--- a/net/ipv6/netfilter/ip6t_owner.c
+++ b/net/ipv6/netfilter/ip6t_owner.c
@@ -26,6 +26,7 @@ static int
26match(const struct sk_buff *skb, 26match(const struct sk_buff *skb,
27 const struct net_device *in, 27 const struct net_device *in,
28 const struct net_device *out, 28 const struct net_device *out,
29 const struct xt_match *match,
29 const void *matchinfo, 30 const void *matchinfo,
30 int offset, 31 int offset,
31 unsigned int protoff, 32 unsigned int protoff,
@@ -54,34 +55,27 @@ match(const struct sk_buff *skb,
54static int 55static int
55checkentry(const char *tablename, 56checkentry(const char *tablename,
56 const void *ip, 57 const void *ip,
58 const struct xt_match *match,
57 void *matchinfo, 59 void *matchinfo,
58 unsigned int matchsize, 60 unsigned int matchsize,
59 unsigned int hook_mask) 61 unsigned int hook_mask)
60{ 62{
61 const struct ip6t_owner_info *info = matchinfo; 63 const struct ip6t_owner_info *info = matchinfo;
62 64
63 if (hook_mask
64 & ~((1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING))) {
65 printk("ip6t_owner: only valid for LOCAL_OUT or POST_ROUTING.\n");
66 return 0;
67 }
68
69 if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_owner_info)))
70 return 0;
71
72 if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) { 65 if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) {
73 printk("ipt_owner: pid and sid matching " 66 printk("ipt_owner: pid and sid matching "
74 "not supported anymore\n"); 67 "not supported anymore\n");
75 return 0; 68 return 0;
76 } 69 }
77
78 return 1; 70 return 1;
79} 71}
80 72
81static struct ip6t_match owner_match = { 73static struct ip6t_match owner_match = {
82 .name = "owner", 74 .name = "owner",
83 .match = &match, 75 .match = match,
84 .checkentry = &checkentry, 76 .matchsize = sizeof(struct ip6t_owner_info),
77 .hooks = (1 << NF_IP6_LOCAL_OUT) | (1 << NF_IP6_POST_ROUTING),
78 .checkentry = checkentry,
85 .me = THIS_MODULE, 79 .me = THIS_MODULE,
86}; 80};
87 81
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c
deleted file mode 100644
index 3d39ec924041..000000000000
--- a/net/ipv6/netfilter/ip6t_policy.c
+++ /dev/null
@@ -1,176 +0,0 @@
1/* IP tables module for matching IPsec policy
2 *
3 * Copyright (c) 2004,2005 Patrick McHardy, <kaber@trash.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/kernel.h>
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/init.h>
15#include <net/xfrm.h>
16
17#include <linux/netfilter_ipv6.h>
18#include <linux/netfilter_ipv6/ip6_tables.h>
19#include <linux/netfilter_ipv6/ip6t_policy.h>
20
21MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
22MODULE_DESCRIPTION("IPtables IPsec policy matching module");
23MODULE_LICENSE("GPL");
24
25
26static inline int
27match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
28{
29#define MATCH_ADDR(x,y,z) (!e->match.x || \
30 ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \
31 ^ e->invert.x))
32#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
33
34 return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
35 MATCH_ADDR(daddr, dmask, (struct in6_addr *)&x->id.daddr.a6) &&
36 MATCH(proto, x->id.proto) &&
37 MATCH(mode, x->props.mode) &&
38 MATCH(spi, x->id.spi) &&
39 MATCH(reqid, x->props.reqid);
40}
41
42static int
43match_policy_in(const struct sk_buff *skb, const struct ip6t_policy_info *info)
44{
45 const struct ip6t_policy_elem *e;
46 struct sec_path *sp = skb->sp;
47 int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
48 int i, pos;
49
50 if (sp == NULL)
51 return -1;
52 if (strict && info->len != sp->len)
53 return 0;
54
55 for (i = sp->len - 1; i >= 0; i--) {
56 pos = strict ? i - sp->len + 1 : 0;
57 if (pos >= info->len)
58 return 0;
59 e = &info->pol[pos];
60
61 if (match_xfrm_state(sp->x[i].xvec, e)) {
62 if (!strict)
63 return 1;
64 } else if (strict)
65 return 0;
66 }
67
68 return strict ? 1 : 0;
69}
70
71static int
72match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
73{
74 const struct ip6t_policy_elem *e;
75 struct dst_entry *dst = skb->dst;
76 int strict = info->flags & IP6T_POLICY_MATCH_STRICT;
77 int i, pos;
78
79 if (dst->xfrm == NULL)
80 return -1;
81
82 for (i = 0; dst && dst->xfrm; dst = dst->child, i++) {
83 pos = strict ? i : 0;
84 if (pos >= info->len)
85 return 0;
86 e = &info->pol[pos];
87
88 if (match_xfrm_state(dst->xfrm, e)) {
89 if (!strict)
90 return 1;
91 } else if (strict)
92 return 0;
93 }
94
95 return strict ? i == info->len : 0;
96}
97
98static int match(const struct sk_buff *skb,
99 const struct net_device *in,
100 const struct net_device *out,
101 const void *matchinfo,
102 int offset,
103 unsigned int protoff,
104 int *hotdrop)
105{
106 const struct ip6t_policy_info *info = matchinfo;
107 int ret;
108
109 if (info->flags & IP6T_POLICY_MATCH_IN)
110 ret = match_policy_in(skb, info);
111 else
112 ret = match_policy_out(skb, info);
113
114 if (ret < 0)
115 ret = info->flags & IP6T_POLICY_MATCH_NONE ? 1 : 0;
116 else if (info->flags & IP6T_POLICY_MATCH_NONE)
117 ret = 0;
118
119 return ret;
120}
121
122static int checkentry(const char *tablename, const void *ip_void,
123 void *matchinfo, unsigned int matchsize,
124 unsigned int hook_mask)
125{
126 struct ip6t_policy_info *info = matchinfo;
127
128 if (matchsize != IP6T_ALIGN(sizeof(*info))) {
129 printk(KERN_ERR "ip6t_policy: matchsize %u != %zu\n",
130 matchsize, IP6T_ALIGN(sizeof(*info)));
131 return 0;
132 }
133 if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))) {
134 printk(KERN_ERR "ip6t_policy: neither incoming nor "
135 "outgoing policy selected\n");
136 return 0;
137 }
138 if (hook_mask & (1 << NF_IP6_PRE_ROUTING | 1 << NF_IP6_LOCAL_IN)
139 && info->flags & IP6T_POLICY_MATCH_OUT) {
140 printk(KERN_ERR "ip6t_policy: output policy not valid in "
141 "PRE_ROUTING and INPUT\n");
142 return 0;
143 }
144 if (hook_mask & (1 << NF_IP6_POST_ROUTING | 1 << NF_IP6_LOCAL_OUT)
145 && info->flags & IP6T_POLICY_MATCH_IN) {
146 printk(KERN_ERR "ip6t_policy: input policy not valid in "
147 "POST_ROUTING and OUTPUT\n");
148 return 0;
149 }
150 if (info->len > IP6T_POLICY_MAX_ELEM) {
151 printk(KERN_ERR "ip6t_policy: too many policy elements\n");
152 return 0;
153 }
154
155 return 1;
156}
157
158static struct ip6t_match policy_match = {
159 .name = "policy",
160 .match = match,
161 .checkentry = checkentry,
162 .me = THIS_MODULE,
163};
164
165static int __init init(void)
166{
167 return ip6t_register_match(&policy_match);
168}
169
170static void __exit fini(void)
171{
172 ip6t_unregister_match(&policy_match);
173}
174
175module_init(init);
176module_exit(fini);
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 8f82476dc89e..4c6b55bb225b 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -45,6 +45,7 @@ static int
45match(const struct sk_buff *skb, 45match(const struct sk_buff *skb,
46 const struct net_device *in, 46 const struct net_device *in,
47 const struct net_device *out, 47 const struct net_device *out,
48 const struct xt_match *match,
48 const void *matchinfo, 49 const void *matchinfo,
49 int offset, 50 int offset,
50 unsigned int protoff, 51 unsigned int protoff,
@@ -194,17 +195,13 @@ match(const struct sk_buff *skb,
194static int 195static int
195checkentry(const char *tablename, 196checkentry(const char *tablename,
196 const void *entry, 197 const void *entry,
198 const struct xt_match *match,
197 void *matchinfo, 199 void *matchinfo,
198 unsigned int matchinfosize, 200 unsigned int matchinfosize,
199 unsigned int hook_mask) 201 unsigned int hook_mask)
200{ 202{
201 const struct ip6t_rt *rtinfo = matchinfo; 203 const struct ip6t_rt *rtinfo = matchinfo;
202 204
203 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
204 DEBUGP("ip6t_rt: matchsize %u != %u\n",
205 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
206 return 0;
207 }
208 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) { 205 if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
209 DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags); 206 DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
210 return 0; 207 return 0;
@@ -222,8 +219,9 @@ checkentry(const char *tablename,
222 219
223static struct ip6t_match rt_match = { 220static struct ip6t_match rt_match = {
224 .name = "rt", 221 .name = "rt",
225 .match = &match, 222 .match = match,
226 .checkentry = &checkentry, 223 .matchsize = sizeof(struct ip6t_rt),
224 .checkentry = checkentry,
227 .me = THIS_MODULE, 225 .me = THIS_MODULE,
228}; 226};
229 227
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index ac702a29dd16..ac35f9526368 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -179,31 +179,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
179 int (*okfn)(struct sk_buff *)) 179 int (*okfn)(struct sk_buff *))
180{ 180{
181 struct nf_conn *ct; 181 struct nf_conn *ct;
182 struct nf_conn_help *help;
182 enum ip_conntrack_info ctinfo; 183 enum ip_conntrack_info ctinfo;
184 unsigned int ret, protoff;
185 unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
186 - (*pskb)->data;
187 unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
188
183 189
184 /* This is where we call the helper: as the packet goes out. */ 190 /* This is where we call the helper: as the packet goes out. */
185 ct = nf_ct_get(*pskb, &ctinfo); 191 ct = nf_ct_get(*pskb, &ctinfo);
186 if (ct && ct->helper) { 192 if (!ct)
187 unsigned int ret, protoff; 193 goto out;
188 unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1)
189 - (*pskb)->data;
190 unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr;
191
192 protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
193 (*pskb)->len - extoff);
194 if (protoff < 0 || protoff > (*pskb)->len ||
195 pnum == NEXTHDR_FRAGMENT) {
196 DEBUGP("proto header not found\n");
197 return NF_ACCEPT;
198 }
199 194
200 ret = ct->helper->help(pskb, protoff, ct, ctinfo); 195 help = nfct_help(ct);
201 if (ret != NF_ACCEPT) 196 if (!help || !help->helper)
202 return ret; 197 goto out;
198
199 protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
200 (*pskb)->len - extoff);
201 if (protoff < 0 || protoff > (*pskb)->len ||
202 pnum == NEXTHDR_FRAGMENT) {
203 DEBUGP("proto header not found\n");
204 return NF_ACCEPT;
203 } 205 }
204 206
207 ret = help->helper->help(pskb, protoff, ct, ctinfo);
208 if (ret != NF_ACCEPT)
209 return ret;
210out:
205 /* We've seen it coming out the other side: confirm it */ 211 /* We've seen it coming out the other side: confirm it */
206
207 return nf_conntrack_confirm(pskb); 212 return nf_conntrack_confirm(pskb);
208} 213}
209 214
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 84ef9a13108d..3e319035f82d 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -313,8 +313,8 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
313#ifdef CONFIG_SMP 313#ifdef CONFIG_SMP
314 hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { 314 hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
315 if (fq->id == fq_in->id && 315 if (fq->id == fq_in->id &&
316 !ipv6_addr_cmp(&fq_in->saddr, &fq->saddr) && 316 ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
317 !ipv6_addr_cmp(&fq_in->daddr, &fq->daddr)) { 317 ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
318 atomic_inc(&fq->refcnt); 318 atomic_inc(&fq->refcnt);
319 write_unlock(&nf_ct_frag6_lock); 319 write_unlock(&nf_ct_frag6_lock);
320 fq_in->last_in |= COMPLETE; 320 fq_in->last_in |= COMPLETE;
@@ -376,8 +376,8 @@ fq_find(u32 id, struct in6_addr *src, struct in6_addr *dst)
376 read_lock(&nf_ct_frag6_lock); 376 read_lock(&nf_ct_frag6_lock);
377 hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) { 377 hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
378 if (fq->id == id && 378 if (fq->id == id &&
379 !ipv6_addr_cmp(src, &fq->saddr) && 379 ipv6_addr_equal(src, &fq->saddr) &&
380 !ipv6_addr_cmp(dst, &fq->daddr)) { 380 ipv6_addr_equal(dst, &fq->daddr)) {
381 atomic_inc(&fq->refcnt); 381 atomic_inc(&fq->refcnt);
382 read_unlock(&nf_ct_frag6_lock); 382 read_unlock(&nf_ct_frag6_lock);
383 return fq; 383 return fq;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index ae20a0ec9bd8..fa1ce0ae123e 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -859,29 +859,12 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname,
859} 859}
860 860
861 861
862static int rawv6_setsockopt(struct sock *sk, int level, int optname, 862static int do_rawv6_setsockopt(struct sock *sk, int level, int optname,
863 char __user *optval, int optlen) 863 char __user *optval, int optlen)
864{ 864{
865 struct raw6_sock *rp = raw6_sk(sk); 865 struct raw6_sock *rp = raw6_sk(sk);
866 int val; 866 int val;
867 867
868 switch(level) {
869 case SOL_RAW:
870 break;
871
872 case SOL_ICMPV6:
873 if (inet_sk(sk)->num != IPPROTO_ICMPV6)
874 return -EOPNOTSUPP;
875 return rawv6_seticmpfilter(sk, level, optname, optval,
876 optlen);
877 case SOL_IPV6:
878 if (optname == IPV6_CHECKSUM)
879 break;
880 default:
881 return ipv6_setsockopt(sk, level, optname, optval,
882 optlen);
883 };
884
885 if (get_user(val, (int __user *)optval)) 868 if (get_user(val, (int __user *)optval))
886 return -EFAULT; 869 return -EFAULT;
887 870
@@ -906,12 +889,9 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
906 } 889 }
907} 890}
908 891
909static int rawv6_getsockopt(struct sock *sk, int level, int optname, 892static int rawv6_setsockopt(struct sock *sk, int level, int optname,
910 char __user *optval, int __user *optlen) 893 char __user *optval, int optlen)
911{ 894{
912 struct raw6_sock *rp = raw6_sk(sk);
913 int val, len;
914
915 switch(level) { 895 switch(level) {
916 case SOL_RAW: 896 case SOL_RAW:
917 break; 897 break;
@@ -919,15 +899,45 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
919 case SOL_ICMPV6: 899 case SOL_ICMPV6:
920 if (inet_sk(sk)->num != IPPROTO_ICMPV6) 900 if (inet_sk(sk)->num != IPPROTO_ICMPV6)
921 return -EOPNOTSUPP; 901 return -EOPNOTSUPP;
922 return rawv6_geticmpfilter(sk, level, optname, optval, 902 return rawv6_seticmpfilter(sk, level, optname, optval,
923 optlen); 903 optlen);
924 case SOL_IPV6: 904 case SOL_IPV6:
925 if (optname == IPV6_CHECKSUM) 905 if (optname == IPV6_CHECKSUM)
926 break; 906 break;
927 default: 907 default:
928 return ipv6_getsockopt(sk, level, optname, optval, 908 return ipv6_setsockopt(sk, level, optname, optval,
929 optlen); 909 optlen);
930 }; 910 };
911 return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
912}
913
914#ifdef CONFIG_COMPAT
915static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname,
916 char __user *optval, int optlen)
917{
918 switch (level) {
919 case SOL_RAW:
920 break;
921 case SOL_ICMPV6:
922 if (inet_sk(sk)->num != IPPROTO_ICMPV6)
923 return -EOPNOTSUPP;
924 return rawv6_seticmpfilter(sk, level, optname, optval, optlen);
925 case SOL_IPV6:
926 if (optname == IPV6_CHECKSUM)
927 break;
928 default:
929 return compat_ipv6_setsockopt(sk, level, optname,
930 optval, optlen);
931 };
932 return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
933}
934#endif
935
936static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
937 char __user *optval, int __user *optlen)
938{
939 struct raw6_sock *rp = raw6_sk(sk);
940 int val, len;
931 941
932 if (get_user(len,optlen)) 942 if (get_user(len,optlen))
933 return -EFAULT; 943 return -EFAULT;
@@ -953,6 +963,50 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
953 return 0; 963 return 0;
954} 964}
955 965
966static int rawv6_getsockopt(struct sock *sk, int level, int optname,
967 char __user *optval, int __user *optlen)
968{
969 switch(level) {
970 case SOL_RAW:
971 break;
972
973 case SOL_ICMPV6:
974 if (inet_sk(sk)->num != IPPROTO_ICMPV6)
975 return -EOPNOTSUPP;
976 return rawv6_geticmpfilter(sk, level, optname, optval,
977 optlen);
978 case SOL_IPV6:
979 if (optname == IPV6_CHECKSUM)
980 break;
981 default:
982 return ipv6_getsockopt(sk, level, optname, optval,
983 optlen);
984 };
985 return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
986}
987
988#ifdef CONFIG_COMPAT
989static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname,
990 char __user *optval, int __user *optlen)
991{
992 switch (level) {
993 case SOL_RAW:
994 break;
995 case SOL_ICMPV6:
996 if (inet_sk(sk)->num != IPPROTO_ICMPV6)
997 return -EOPNOTSUPP;
998 return rawv6_geticmpfilter(sk, level, optname, optval, optlen);
999 case SOL_IPV6:
1000 if (optname == IPV6_CHECKSUM)
1001 break;
1002 default:
1003 return compat_ipv6_getsockopt(sk, level, optname,
1004 optval, optlen);
1005 };
1006 return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
1007}
1008#endif
1009
956static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) 1010static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg)
957{ 1011{
958 switch(cmd) { 1012 switch(cmd) {
@@ -998,23 +1052,27 @@ static int rawv6_init_sk(struct sock *sk)
998} 1052}
999 1053
1000struct proto rawv6_prot = { 1054struct proto rawv6_prot = {
1001 .name = "RAWv6", 1055 .name = "RAWv6",
1002 .owner = THIS_MODULE, 1056 .owner = THIS_MODULE,
1003 .close = rawv6_close, 1057 .close = rawv6_close,
1004 .connect = ip6_datagram_connect, 1058 .connect = ip6_datagram_connect,
1005 .disconnect = udp_disconnect, 1059 .disconnect = udp_disconnect,
1006 .ioctl = rawv6_ioctl, 1060 .ioctl = rawv6_ioctl,
1007 .init = rawv6_init_sk, 1061 .init = rawv6_init_sk,
1008 .destroy = inet6_destroy_sock, 1062 .destroy = inet6_destroy_sock,
1009 .setsockopt = rawv6_setsockopt, 1063 .setsockopt = rawv6_setsockopt,
1010 .getsockopt = rawv6_getsockopt, 1064 .getsockopt = rawv6_getsockopt,
1011 .sendmsg = rawv6_sendmsg, 1065 .sendmsg = rawv6_sendmsg,
1012 .recvmsg = rawv6_recvmsg, 1066 .recvmsg = rawv6_recvmsg,
1013 .bind = rawv6_bind, 1067 .bind = rawv6_bind,
1014 .backlog_rcv = rawv6_rcv_skb, 1068 .backlog_rcv = rawv6_rcv_skb,
1015 .hash = raw_v6_hash, 1069 .hash = raw_v6_hash,
1016 .unhash = raw_v6_unhash, 1070 .unhash = raw_v6_unhash,
1017 .obj_size = sizeof(struct raw6_sock), 1071 .obj_size = sizeof(struct raw6_sock),
1072#ifdef CONFIG_COMPAT
1073 .compat_setsockopt = compat_rawv6_setsockopt,
1074 .compat_getsockopt = compat_rawv6_getsockopt,
1075#endif
1018}; 1076};
1019 1077
1020#ifdef CONFIG_PROC_FS 1078#ifdef CONFIG_PROC_FS
@@ -1140,7 +1198,7 @@ static int raw6_seq_open(struct inode *inode, struct file *file)
1140{ 1198{
1141 struct seq_file *seq; 1199 struct seq_file *seq;
1142 int rc = -ENOMEM; 1200 int rc = -ENOMEM;
1143 struct raw6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); 1201 struct raw6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
1144 if (!s) 1202 if (!s)
1145 goto out; 1203 goto out;
1146 rc = seq_open(file, &raw6_seq_ops); 1204 rc = seq_open(file, &raw6_seq_ops);
@@ -1148,7 +1206,6 @@ static int raw6_seq_open(struct inode *inode, struct file *file)
1148 goto out_kfree; 1206 goto out_kfree;
1149 seq = file->private_data; 1207 seq = file->private_data;
1150 seq->private = s; 1208 seq->private = s;
1151 memset(s, 0, sizeof(*s));
1152out: 1209out:
1153 return rc; 1210 return rc;
1154out_kfree: 1211out_kfree:
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 15e1456b3f18..b67a45fb93e9 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -203,7 +203,7 @@ static inline void frag_free_queue(struct frag_queue *fq, int *work)
203 203
204static inline struct frag_queue *frag_alloc_queue(void) 204static inline struct frag_queue *frag_alloc_queue(void)
205{ 205{
206 struct frag_queue *fq = kmalloc(sizeof(struct frag_queue), GFP_ATOMIC); 206 struct frag_queue *fq = kzalloc(sizeof(struct frag_queue), GFP_ATOMIC);
207 207
208 if(!fq) 208 if(!fq)
209 return NULL; 209 return NULL;
@@ -288,6 +288,7 @@ static void ip6_evictor(void)
288static void ip6_frag_expire(unsigned long data) 288static void ip6_frag_expire(unsigned long data)
289{ 289{
290 struct frag_queue *fq = (struct frag_queue *) data; 290 struct frag_queue *fq = (struct frag_queue *) data;
291 struct net_device *dev;
291 292
292 spin_lock(&fq->lock); 293 spin_lock(&fq->lock);
293 294
@@ -299,22 +300,22 @@ static void ip6_frag_expire(unsigned long data)
299 IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); 300 IP6_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
300 IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); 301 IP6_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
301 302
302 /* Send error only if the first segment arrived. */ 303 /* Don't send error if the first segment did not arrive. */
303 if (fq->last_in&FIRST_IN && fq->fragments) { 304 if (!(fq->last_in&FIRST_IN) || !fq->fragments)
304 struct net_device *dev = dev_get_by_index(fq->iif); 305 goto out;
305 306
306 /* 307 dev = dev_get_by_index(fq->iif);
307 But use as source device on which LAST ARRIVED 308 if (!dev)
308 segment was received. And do not use fq->dev 309 goto out;
309 pointer directly, device might already disappeared. 310
310 */ 311 /*
311 if (dev) { 312 But use as source device on which LAST ARRIVED
312 fq->fragments->dev = dev; 313 segment was received. And do not use fq->dev
313 icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, 314 pointer directly, device might already disappeared.
314 dev); 315 */
315 dev_put(dev); 316 fq->fragments->dev = dev;
316 } 317 icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
317 } 318 dev_put(dev);
318out: 319out:
319 spin_unlock(&fq->lock); 320 spin_unlock(&fq->lock);
320 fq_put(fq, NULL); 321 fq_put(fq, NULL);
@@ -368,8 +369,6 @@ ip6_frag_create(unsigned int hash, u32 id, struct in6_addr *src, struct in6_addr
368 if ((fq = frag_alloc_queue()) == NULL) 369 if ((fq = frag_alloc_queue()) == NULL)
369 goto oom; 370 goto oom;
370 371
371 memset(fq, 0, sizeof(struct frag_queue));
372
373 fq->id = id; 372 fq->id = id;
374 ipv6_addr_copy(&fq->saddr, src); 373 ipv6_addr_copy(&fq->saddr, src);
375 ipv6_addr_copy(&fq->daddr, dst); 374 ipv6_addr_copy(&fq->daddr, dst);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e0d3ad02ffb5..79078747a646 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -72,6 +72,10 @@
72#define RT6_TRACE(x...) do { ; } while (0) 72#define RT6_TRACE(x...) do { ; } while (0)
73#endif 73#endif
74 74
75#define CLONE_OFFLINK_ROUTE 0
76
77#define RT6_SELECT_F_IFACE 0x1
78#define RT6_SELECT_F_REACHABLE 0x2
75 79
76static int ip6_rt_max_size = 4096; 80static int ip6_rt_max_size = 4096;
77static int ip6_rt_gc_min_interval = HZ / 2; 81static int ip6_rt_gc_min_interval = HZ / 2;
@@ -94,6 +98,14 @@ static int ip6_pkt_discard_out(struct sk_buff *skb);
94static void ip6_link_failure(struct sk_buff *skb); 98static void ip6_link_failure(struct sk_buff *skb);
95static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); 99static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
96 100
101#ifdef CONFIG_IPV6_ROUTE_INFO
102static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
103 struct in6_addr *gwaddr, int ifindex,
104 unsigned pref);
105static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
106 struct in6_addr *gwaddr, int ifindex);
107#endif
108
97static struct dst_ops ip6_dst_ops = { 109static struct dst_ops ip6_dst_ops = {
98 .family = AF_INET6, 110 .family = AF_INET6,
99 .protocol = __constant_htons(ETH_P_IPV6), 111 .protocol = __constant_htons(ETH_P_IPV6),
@@ -214,150 +226,211 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
214 return rt; 226 return rt;
215} 227}
216 228
229#ifdef CONFIG_IPV6_ROUTER_PREF
230static void rt6_probe(struct rt6_info *rt)
231{
232 struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL;
233 /*
234 * Okay, this does not seem to be appropriate
235 * for now, however, we need to check if it
236 * is really so; aka Router Reachability Probing.
237 *
238 * Router Reachability Probe MUST be rate-limited
239 * to no more than one per minute.
240 */
241 if (!neigh || (neigh->nud_state & NUD_VALID))
242 return;
243 read_lock_bh(&neigh->lock);
244 if (!(neigh->nud_state & NUD_VALID) &&
245 time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) {
246 struct in6_addr mcaddr;
247 struct in6_addr *target;
248
249 neigh->updated = jiffies;
250 read_unlock_bh(&neigh->lock);
251
252 target = (struct in6_addr *)&neigh->primary_key;
253 addrconf_addr_solict_mult(target, &mcaddr);
254 ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
255 } else
256 read_unlock_bh(&neigh->lock);
257}
258#else
259static inline void rt6_probe(struct rt6_info *rt)
260{
261 return;
262}
263#endif
264
217/* 265/*
218 * pointer to the last default router chosen. BH is disabled locally. 266 * Default Router Selection (RFC 2461 6.3.6)
219 */ 267 */
220static struct rt6_info *rt6_dflt_pointer; 268static int inline rt6_check_dev(struct rt6_info *rt, int oif)
221static DEFINE_SPINLOCK(rt6_dflt_lock); 269{
270 struct net_device *dev = rt->rt6i_dev;
271 if (!oif || dev->ifindex == oif)
272 return 2;
273 if ((dev->flags & IFF_LOOPBACK) &&
274 rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif)
275 return 1;
276 return 0;
277}
222 278
223void rt6_reset_dflt_pointer(struct rt6_info *rt) 279static int inline rt6_check_neigh(struct rt6_info *rt)
224{ 280{
225 spin_lock_bh(&rt6_dflt_lock); 281 struct neighbour *neigh = rt->rt6i_nexthop;
226 if (rt == NULL || rt == rt6_dflt_pointer) { 282 int m = 0;
227 RT6_TRACE("reset default router: %p->NULL\n", rt6_dflt_pointer); 283 if (neigh) {
228 rt6_dflt_pointer = NULL; 284 read_lock_bh(&neigh->lock);
285 if (neigh->nud_state & NUD_VALID)
286 m = 1;
287 read_unlock_bh(&neigh->lock);
229 } 288 }
230 spin_unlock_bh(&rt6_dflt_lock); 289 return m;
231} 290}
232 291
233/* Default Router Selection (RFC 2461 6.3.6) */ 292static int rt6_score_route(struct rt6_info *rt, int oif,
234static struct rt6_info *rt6_best_dflt(struct rt6_info *rt, int oif) 293 int strict)
235{ 294{
236 struct rt6_info *match = NULL; 295 int m = rt6_check_dev(rt, oif);
237 struct rt6_info *sprt; 296 if (!m && (strict & RT6_SELECT_F_IFACE))
238 int mpri = 0; 297 return -1;
239 298#ifdef CONFIG_IPV6_ROUTER_PREF
240 for (sprt = rt; sprt; sprt = sprt->u.next) { 299 m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
241 struct neighbour *neigh; 300#endif
242 int m = 0; 301 if (rt6_check_neigh(rt))
243 302 m |= 16;
244 if (!oif || 303 else if (strict & RT6_SELECT_F_REACHABLE)
245 (sprt->rt6i_dev && 304 return -1;
246 sprt->rt6i_dev->ifindex == oif)) 305 return m;
247 m += 8; 306}
248 307
249 if (rt6_check_expired(sprt)) 308static struct rt6_info *rt6_select(struct rt6_info **head, int oif,
250 continue; 309 int strict)
310{
311 struct rt6_info *match = NULL, *last = NULL;
312 struct rt6_info *rt, *rt0 = *head;
313 u32 metric;
314 int mpri = -1;
251 315
252 if (sprt == rt6_dflt_pointer) 316 RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n",
253 m += 4; 317 __FUNCTION__, head, head ? *head : NULL, oif);
254 318
255 if ((neigh = sprt->rt6i_nexthop) != NULL) { 319 for (rt = rt0, metric = rt0->rt6i_metric;
256 read_lock_bh(&neigh->lock); 320 rt && rt->rt6i_metric == metric;
257 switch (neigh->nud_state) { 321 rt = rt->u.next) {
258 case NUD_REACHABLE: 322 int m;
259 m += 3;
260 break;
261 323
262 case NUD_STALE: 324 if (rt6_check_expired(rt))
263 case NUD_DELAY: 325 continue;
264 case NUD_PROBE:
265 m += 2;
266 break;
267 326
268 case NUD_NOARP: 327 last = rt;
269 case NUD_PERMANENT:
270 m += 1;
271 break;
272 328
273 case NUD_INCOMPLETE: 329 m = rt6_score_route(rt, oif, strict);
274 default: 330 if (m < 0)
275 read_unlock_bh(&neigh->lock);
276 continue;
277 }
278 read_unlock_bh(&neigh->lock);
279 } else {
280 continue; 331 continue;
281 }
282 332
283 if (m > mpri || m >= 12) { 333 if (m > mpri) {
284 match = sprt; 334 rt6_probe(match);
335 match = rt;
285 mpri = m; 336 mpri = m;
286 if (m >= 12) { 337 } else {
287 /* we choose the last default router if it 338 rt6_probe(rt);
288 * is in (probably) reachable state.
289 * If route changed, we should do pmtu
290 * discovery. --yoshfuji
291 */
292 break;
293 }
294 } 339 }
295 } 340 }
296 341
297 spin_lock(&rt6_dflt_lock); 342 if (!match &&
298 if (!match) { 343 (strict & RT6_SELECT_F_REACHABLE) &&
299 /* 344 last && last != rt0) {
300 * No default routers are known to be reachable. 345 /* no entries matched; do round-robin */
301 * SHOULD round robin 346 *head = rt0->u.next;
302 */ 347 rt0->u.next = last->u.next;
303 if (rt6_dflt_pointer) { 348 last->u.next = rt0;
304 for (sprt = rt6_dflt_pointer->u.next;
305 sprt; sprt = sprt->u.next) {
306 if (sprt->u.dst.obsolete <= 0 &&
307 sprt->u.dst.error == 0 &&
308 !rt6_check_expired(sprt)) {
309 match = sprt;
310 break;
311 }
312 }
313 for (sprt = rt;
314 !match && sprt;
315 sprt = sprt->u.next) {
316 if (sprt->u.dst.obsolete <= 0 &&
317 sprt->u.dst.error == 0 &&
318 !rt6_check_expired(sprt)) {
319 match = sprt;
320 break;
321 }
322 if (sprt == rt6_dflt_pointer)
323 break;
324 }
325 }
326 } 349 }
327 350
328 if (match) { 351 RT6_TRACE("%s() => %p, score=%d\n",
329 if (rt6_dflt_pointer != match) 352 __FUNCTION__, match, mpri);
330 RT6_TRACE("changed default router: %p->%p\n", 353
331 rt6_dflt_pointer, match); 354 return (match ? match : &ip6_null_entry);
332 rt6_dflt_pointer = match; 355}
356
357#ifdef CONFIG_IPV6_ROUTE_INFO
358int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
359 struct in6_addr *gwaddr)
360{
361 struct route_info *rinfo = (struct route_info *) opt;
362 struct in6_addr prefix_buf, *prefix;
363 unsigned int pref;
364 u32 lifetime;
365 struct rt6_info *rt;
366
367 if (len < sizeof(struct route_info)) {
368 return -EINVAL;
333 } 369 }
334 spin_unlock(&rt6_dflt_lock);
335 370
336 if (!match) { 371 /* Sanity check for prefix_len and length */
337 /* 372 if (rinfo->length > 3) {
338 * Last Resort: if no default routers found, 373 return -EINVAL;
339 * use addrconf default route. 374 } else if (rinfo->prefix_len > 128) {
340 * We don't record this route. 375 return -EINVAL;
341 */ 376 } else if (rinfo->prefix_len > 64) {
342 for (sprt = ip6_routing_table.leaf; 377 if (rinfo->length < 2) {
343 sprt; sprt = sprt->u.next) { 378 return -EINVAL;
344 if (!rt6_check_expired(sprt) &&
345 (sprt->rt6i_flags & RTF_DEFAULT) &&
346 (!oif ||
347 (sprt->rt6i_dev &&
348 sprt->rt6i_dev->ifindex == oif))) {
349 match = sprt;
350 break;
351 }
352 } 379 }
353 if (!match) { 380 } else if (rinfo->prefix_len > 0) {
354 /* no default route. give up. */ 381 if (rinfo->length < 1) {
355 match = &ip6_null_entry; 382 return -EINVAL;
356 } 383 }
357 } 384 }
358 385
359 return match; 386 pref = rinfo->route_pref;
387 if (pref == ICMPV6_ROUTER_PREF_INVALID)
388 pref = ICMPV6_ROUTER_PREF_MEDIUM;
389
390 lifetime = htonl(rinfo->lifetime);
391 if (lifetime == 0xffffffff) {
392 /* infinity */
393 } else if (lifetime > 0x7fffffff/HZ) {
394 /* Avoid arithmetic overflow */
395 lifetime = 0x7fffffff/HZ - 1;
396 }
397
398 if (rinfo->length == 3)
399 prefix = (struct in6_addr *)rinfo->prefix;
400 else {
401 /* this function is safe */
402 ipv6_addr_prefix(&prefix_buf,
403 (struct in6_addr *)rinfo->prefix,
404 rinfo->prefix_len);
405 prefix = &prefix_buf;
406 }
407
408 rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex);
409
410 if (rt && !lifetime) {
411 ip6_del_rt(rt, NULL, NULL, NULL);
412 rt = NULL;
413 }
414
415 if (!rt && lifetime)
416 rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
417 pref);
418 else if (rt)
419 rt->rt6i_flags = RTF_ROUTEINFO |
420 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
421
422 if (rt) {
423 if (lifetime == 0xffffffff) {
424 rt->rt6i_flags &= ~RTF_EXPIRES;
425 } else {
426 rt->rt6i_expires = jiffies + HZ * lifetime;
427 rt->rt6i_flags |= RTF_EXPIRES;
428 }
429 dst_release(&rt->u.dst);
430 }
431 return 0;
360} 432}
433#endif
361 434
362struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, 435struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
363 int oif, int strict) 436 int oif, int strict)
@@ -397,14 +470,9 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh,
397 return err; 470 return err;
398} 471}
399 472
400/* No rt6_lock! If COW failed, the function returns dead route entry 473static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, struct in6_addr *daddr,
401 with dst->error set to errno value. 474 struct in6_addr *saddr)
402 */
403
404static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
405 struct in6_addr *saddr, struct netlink_skb_parms *req)
406{ 475{
407 int err;
408 struct rt6_info *rt; 476 struct rt6_info *rt;
409 477
410 /* 478 /*
@@ -435,25 +503,30 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr,
435 503
436 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); 504 rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
437 505
438 dst_hold(&rt->u.dst); 506 }
439
440 err = ip6_ins_rt(rt, NULL, NULL, req);
441 if (err == 0)
442 return rt;
443 507
444 rt->u.dst.error = err; 508 return rt;
509}
445 510
446 return rt; 511static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *daddr)
512{
513 struct rt6_info *rt = ip6_rt_copy(ort);
514 if (rt) {
515 ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
516 rt->rt6i_dst.plen = 128;
517 rt->rt6i_flags |= RTF_CACHE;
518 if (rt->rt6i_flags & RTF_REJECT)
519 rt->u.dst.error = ort->u.dst.error;
520 rt->u.dst.flags |= DST_HOST;
521 rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
447 } 522 }
448 dst_hold(&ip6_null_entry.u.dst); 523 return rt;
449 return &ip6_null_entry;
450} 524}
451 525
452#define BACKTRACK() \ 526#define BACKTRACK() \
453if (rt == &ip6_null_entry && strict) { \ 527if (rt == &ip6_null_entry) { \
454 while ((fn = fn->parent) != NULL) { \ 528 while ((fn = fn->parent) != NULL) { \
455 if (fn->fn_flags & RTN_ROOT) { \ 529 if (fn->fn_flags & RTN_ROOT) { \
456 dst_hold(&rt->u.dst); \
457 goto out; \ 530 goto out; \
458 } \ 531 } \
459 if (fn->fn_flags & RTN_RTINFO) \ 532 if (fn->fn_flags & RTN_RTINFO) \
@@ -465,115 +538,138 @@ if (rt == &ip6_null_entry && strict) { \
465void ip6_route_input(struct sk_buff *skb) 538void ip6_route_input(struct sk_buff *skb)
466{ 539{
467 struct fib6_node *fn; 540 struct fib6_node *fn;
468 struct rt6_info *rt; 541 struct rt6_info *rt, *nrt;
469 int strict; 542 int strict;
470 int attempts = 3; 543 int attempts = 3;
544 int err;
545 int reachable = RT6_SELECT_F_REACHABLE;
471 546
472 strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); 547 strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
473 548
474relookup: 549relookup:
475 read_lock_bh(&rt6_lock); 550 read_lock_bh(&rt6_lock);
476 551
552restart_2:
477 fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, 553 fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr,
478 &skb->nh.ipv6h->saddr); 554 &skb->nh.ipv6h->saddr);
479 555
480restart: 556restart:
481 rt = fn->leaf; 557 rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable);
482
483 if ((rt->rt6i_flags & RTF_CACHE)) {
484 rt = rt6_device_match(rt, skb->dev->ifindex, strict);
485 BACKTRACK();
486 dst_hold(&rt->u.dst);
487 goto out;
488 }
489
490 rt = rt6_device_match(rt, skb->dev->ifindex, strict);
491 BACKTRACK(); 558 BACKTRACK();
559 if (rt == &ip6_null_entry ||
560 rt->rt6i_flags & RTF_CACHE)
561 goto out;
492 562
493 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { 563 dst_hold(&rt->u.dst);
494 struct rt6_info *nrt; 564 read_unlock_bh(&rt6_lock);
495 dst_hold(&rt->u.dst);
496 read_unlock_bh(&rt6_lock);
497 565
498 nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr, 566 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
499 &skb->nh.ipv6h->saddr, 567 nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr);
500 &NETLINK_CB(skb)); 568 else {
569#if CLONE_OFFLINK_ROUTE
570 nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr);
571#else
572 goto out2;
573#endif
574 }
501 575
502 dst_release(&rt->u.dst); 576 dst_release(&rt->u.dst);
503 rt = nrt; 577 rt = nrt ? : &ip6_null_entry;
504 578
505 if (rt->u.dst.error != -EEXIST || --attempts <= 0) 579 dst_hold(&rt->u.dst);
580 if (nrt) {
581 err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb));
582 if (!err)
506 goto out2; 583 goto out2;
507
508 /* Race condition! In the gap, when rt6_lock was
509 released someone could insert this route. Relookup.
510 */
511 dst_release(&rt->u.dst);
512 goto relookup;
513 } 584 }
514 dst_hold(&rt->u.dst); 585
586 if (--attempts <= 0)
587 goto out2;
588
589 /*
590 * Race condition! In the gap, when rt6_lock was
591 * released someone could insert this route. Relookup.
592 */
593 dst_release(&rt->u.dst);
594 goto relookup;
515 595
516out: 596out:
597 if (reachable) {
598 reachable = 0;
599 goto restart_2;
600 }
601 dst_hold(&rt->u.dst);
517 read_unlock_bh(&rt6_lock); 602 read_unlock_bh(&rt6_lock);
518out2: 603out2:
519 rt->u.dst.lastuse = jiffies; 604 rt->u.dst.lastuse = jiffies;
520 rt->u.dst.__use++; 605 rt->u.dst.__use++;
521 skb->dst = (struct dst_entry *) rt; 606 skb->dst = (struct dst_entry *) rt;
607 return;
522} 608}
523 609
524struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) 610struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
525{ 611{
526 struct fib6_node *fn; 612 struct fib6_node *fn;
527 struct rt6_info *rt; 613 struct rt6_info *rt, *nrt;
528 int strict; 614 int strict;
529 int attempts = 3; 615 int attempts = 3;
616 int err;
617 int reachable = RT6_SELECT_F_REACHABLE;
530 618
531 strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL); 619 strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0;
532 620
533relookup: 621relookup:
534 read_lock_bh(&rt6_lock); 622 read_lock_bh(&rt6_lock);
535 623
624restart_2:
536 fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); 625 fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src);
537 626
538restart: 627restart:
539 rt = fn->leaf; 628 rt = rt6_select(&fn->leaf, fl->oif, strict | reachable);
540 629 BACKTRACK();
541 if ((rt->rt6i_flags & RTF_CACHE)) { 630 if (rt == &ip6_null_entry ||
542 rt = rt6_device_match(rt, fl->oif, strict); 631 rt->rt6i_flags & RTF_CACHE)
543 BACKTRACK();
544 dst_hold(&rt->u.dst);
545 goto out; 632 goto out;
546 }
547 if (rt->rt6i_flags & RTF_DEFAULT) {
548 if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
549 rt = rt6_best_dflt(rt, fl->oif);
550 } else {
551 rt = rt6_device_match(rt, fl->oif, strict);
552 BACKTRACK();
553 }
554 633
555 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { 634 dst_hold(&rt->u.dst);
556 struct rt6_info *nrt; 635 read_unlock_bh(&rt6_lock);
557 dst_hold(&rt->u.dst);
558 read_unlock_bh(&rt6_lock);
559 636
560 nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src, NULL); 637 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
638 nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
639 else {
640#if CLONE_OFFLINK_ROUTE
641 nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
642#else
643 goto out2;
644#endif
645 }
561 646
562 dst_release(&rt->u.dst); 647 dst_release(&rt->u.dst);
563 rt = nrt; 648 rt = nrt ? : &ip6_null_entry;
564 649
565 if (rt->u.dst.error != -EEXIST || --attempts <= 0) 650 dst_hold(&rt->u.dst);
651 if (nrt) {
652 err = ip6_ins_rt(nrt, NULL, NULL, NULL);
653 if (!err)
566 goto out2; 654 goto out2;
567
568 /* Race condition! In the gap, when rt6_lock was
569 released someone could insert this route. Relookup.
570 */
571 dst_release(&rt->u.dst);
572 goto relookup;
573 } 655 }
574 dst_hold(&rt->u.dst); 656
657 if (--attempts <= 0)
658 goto out2;
659
660 /*
661 * Race condition! In the gap, when rt6_lock was
662 * released someone could insert this route. Relookup.
663 */
664 dst_release(&rt->u.dst);
665 goto relookup;
575 666
576out: 667out:
668 if (reachable) {
669 reachable = 0;
670 goto restart_2;
671 }
672 dst_hold(&rt->u.dst);
577 read_unlock_bh(&rt6_lock); 673 read_unlock_bh(&rt6_lock);
578out2: 674out2:
579 rt->u.dst.lastuse = jiffies; 675 rt->u.dst.lastuse = jiffies;
@@ -999,8 +1095,6 @@ int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct
999 1095
1000 write_lock_bh(&rt6_lock); 1096 write_lock_bh(&rt6_lock);
1001 1097
1002 rt6_reset_dflt_pointer(NULL);
1003
1004 err = fib6_del(rt, nlh, _rtattr, req); 1098 err = fib6_del(rt, nlh, _rtattr, req);
1005 dst_release(&rt->u.dst); 1099 dst_release(&rt->u.dst);
1006 1100
@@ -1050,59 +1144,63 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r
1050void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, 1144void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
1051 struct neighbour *neigh, u8 *lladdr, int on_link) 1145 struct neighbour *neigh, u8 *lladdr, int on_link)
1052{ 1146{
1053 struct rt6_info *rt, *nrt; 1147 struct rt6_info *rt, *nrt = NULL;
1054 1148 int strict;
1055 /* Locate old route to this destination. */ 1149 struct fib6_node *fn;
1056 rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
1057
1058 if (rt == NULL)
1059 return;
1060
1061 if (neigh->dev != rt->rt6i_dev)
1062 goto out;
1063 1150
1064 /* 1151 /*
1065 * Current route is on-link; redirect is always invalid. 1152 * Get the "current" route for this destination and
1066 * 1153 * check if the redirect has come from approriate router.
1067 * Seems, previous statement is not true. It could 1154 *
1068 * be node, which looks for us as on-link (f.e. proxy ndisc) 1155 * RFC 2461 specifies that redirects should only be
1069 * But then router serving it might decide, that we should 1156 * accepted if they come from the nexthop to the target.
1070 * know truth 8)8) --ANK (980726). 1157 * Due to the way the routes are chosen, this notion
1158 * is a bit fuzzy and one might need to check all possible
1159 * routes.
1071 */ 1160 */
1072 if (!(rt->rt6i_flags&RTF_GATEWAY)) 1161 strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
1073 goto out;
1074 1162
1075 /* 1163 read_lock_bh(&rt6_lock);
1076 * RFC 2461 specifies that redirects should only be 1164 fn = fib6_lookup(&ip6_routing_table, dest, NULL);
1077 * accepted if they come from the nexthop to the target. 1165restart:
1078 * Due to the way default routers are chosen, this notion 1166 for (rt = fn->leaf; rt; rt = rt->u.next) {
1079 * is a bit fuzzy and one might need to check all default 1167 /*
1080 * routers. 1168 * Current route is on-link; redirect is always invalid.
1081 */ 1169 *
1082 if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) { 1170 * Seems, previous statement is not true. It could
1083 if (rt->rt6i_flags & RTF_DEFAULT) { 1171 * be node, which looks for us as on-link (f.e. proxy ndisc)
1084 struct rt6_info *rt1; 1172 * But then router serving it might decide, that we should
1085 1173 * know truth 8)8) --ANK (980726).
1086 read_lock(&rt6_lock); 1174 */
1087 for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) { 1175 if (rt6_check_expired(rt))
1088 if (ipv6_addr_equal(saddr, &rt1->rt6i_gateway)) { 1176 continue;
1089 dst_hold(&rt1->u.dst); 1177 if (!(rt->rt6i_flags & RTF_GATEWAY))
1090 dst_release(&rt->u.dst); 1178 continue;
1091 read_unlock(&rt6_lock); 1179 if (neigh->dev != rt->rt6i_dev)
1092 rt = rt1; 1180 continue;
1093 goto source_ok; 1181 if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway))
1094 } 1182 continue;
1095 } 1183 break;
1096 read_unlock(&rt6_lock); 1184 }
1185 if (rt)
1186 dst_hold(&rt->u.dst);
1187 else if (strict) {
1188 while ((fn = fn->parent) != NULL) {
1189 if (fn->fn_flags & RTN_ROOT)
1190 break;
1191 if (fn->fn_flags & RTN_RTINFO)
1192 goto restart;
1097 } 1193 }
1194 }
1195 read_unlock_bh(&rt6_lock);
1196
1197 if (!rt) {
1098 if (net_ratelimit()) 1198 if (net_ratelimit())
1099 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " 1199 printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
1100 "for redirect target\n"); 1200 "for redirect target\n");
1101 goto out; 1201 return;
1102 } 1202 }
1103 1203
1104source_ok:
1105
1106 /* 1204 /*
1107 * We have finally decided to accept it. 1205 * We have finally decided to accept it.
1108 */ 1206 */
@@ -1210,38 +1308,27 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
1210 1. It is connected route. Action: COW 1308 1. It is connected route. Action: COW
1211 2. It is gatewayed route or NONEXTHOP route. Action: clone it. 1309 2. It is gatewayed route or NONEXTHOP route. Action: clone it.
1212 */ 1310 */
1213 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { 1311 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
1214 nrt = rt6_cow(rt, daddr, saddr, NULL); 1312 nrt = rt6_alloc_cow(rt, daddr, saddr);
1215 if (!nrt->u.dst.error) { 1313 else
1216 nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; 1314 nrt = rt6_alloc_clone(rt, daddr);
1217 if (allfrag) 1315
1218 nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; 1316 if (nrt) {
1219 /* According to RFC 1981, detecting PMTU increase shouldn't be
1220 happened within 5 mins, the recommended timer is 10 mins.
1221 Here this route expiration time is set to ip6_rt_mtu_expires
1222 which is 10 mins. After 10 mins the decreased pmtu is expired
1223 and detecting PMTU increase will be automatically happened.
1224 */
1225 dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
1226 nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
1227 }
1228 dst_release(&nrt->u.dst);
1229 } else {
1230 nrt = ip6_rt_copy(rt);
1231 if (nrt == NULL)
1232 goto out;
1233 ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
1234 nrt->rt6i_dst.plen = 128;
1235 nrt->u.dst.flags |= DST_HOST;
1236 nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
1237 dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
1238 nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
1239 nrt->u.dst.metrics[RTAX_MTU-1] = pmtu; 1317 nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
1240 if (allfrag) 1318 if (allfrag)
1241 nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; 1319 nrt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
1320
1321 /* According to RFC 1981, detecting PMTU increase shouldn't be
1322 * happened within 5 mins, the recommended timer is 10 mins.
1323 * Here this route expiration time is set to ip6_rt_mtu_expires
1324 * which is 10 mins. After 10 mins the decreased pmtu is expired
1325 * and detecting PMTU increase will be automatically happened.
1326 */
1327 dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
1328 nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
1329
1242 ip6_ins_rt(nrt, NULL, NULL, NULL); 1330 ip6_ins_rt(nrt, NULL, NULL, NULL);
1243 } 1331 }
1244
1245out: 1332out:
1246 dst_release(&rt->u.dst); 1333 dst_release(&rt->u.dst);
1247} 1334}
@@ -1280,6 +1367,57 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
1280 return rt; 1367 return rt;
1281} 1368}
1282 1369
1370#ifdef CONFIG_IPV6_ROUTE_INFO
1371static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
1372 struct in6_addr *gwaddr, int ifindex)
1373{
1374 struct fib6_node *fn;
1375 struct rt6_info *rt = NULL;
1376
1377 write_lock_bh(&rt6_lock);
1378 fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0);
1379 if (!fn)
1380 goto out;
1381
1382 for (rt = fn->leaf; rt; rt = rt->u.next) {
1383 if (rt->rt6i_dev->ifindex != ifindex)
1384 continue;
1385 if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
1386 continue;
1387 if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr))
1388 continue;
1389 dst_hold(&rt->u.dst);
1390 break;
1391 }
1392out:
1393 write_unlock_bh(&rt6_lock);
1394 return rt;
1395}
1396
1397static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
1398 struct in6_addr *gwaddr, int ifindex,
1399 unsigned pref)
1400{
1401 struct in6_rtmsg rtmsg;
1402
1403 memset(&rtmsg, 0, sizeof(rtmsg));
1404 rtmsg.rtmsg_type = RTMSG_NEWROUTE;
1405 ipv6_addr_copy(&rtmsg.rtmsg_dst, prefix);
1406 rtmsg.rtmsg_dst_len = prefixlen;
1407 ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
1408 rtmsg.rtmsg_metric = 1024;
1409 rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref);
1410 /* We should treat it as a default route if prefix length is 0. */
1411 if (!prefixlen)
1412 rtmsg.rtmsg_flags |= RTF_DEFAULT;
1413 rtmsg.rtmsg_ifindex = ifindex;
1414
1415 ip6_route_add(&rtmsg, NULL, NULL, NULL);
1416
1417 return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
1418}
1419#endif
1420
1283struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) 1421struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev)
1284{ 1422{
1285 struct rt6_info *rt; 1423 struct rt6_info *rt;
@@ -1290,6 +1428,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
1290 write_lock_bh(&rt6_lock); 1428 write_lock_bh(&rt6_lock);
1291 for (rt = fn->leaf; rt; rt=rt->u.next) { 1429 for (rt = fn->leaf; rt; rt=rt->u.next) {
1292 if (dev == rt->rt6i_dev && 1430 if (dev == rt->rt6i_dev &&
1431 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
1293 ipv6_addr_equal(&rt->rt6i_gateway, addr)) 1432 ipv6_addr_equal(&rt->rt6i_gateway, addr))
1294 break; 1433 break;
1295 } 1434 }
@@ -1300,7 +1439,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
1300} 1439}
1301 1440
1302struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, 1441struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
1303 struct net_device *dev) 1442 struct net_device *dev,
1443 unsigned int pref)
1304{ 1444{
1305 struct in6_rtmsg rtmsg; 1445 struct in6_rtmsg rtmsg;
1306 1446
@@ -1308,7 +1448,8 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
1308 rtmsg.rtmsg_type = RTMSG_NEWROUTE; 1448 rtmsg.rtmsg_type = RTMSG_NEWROUTE;
1309 ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr); 1449 ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
1310 rtmsg.rtmsg_metric = 1024; 1450 rtmsg.rtmsg_metric = 1024;
1311 rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES; 1451 rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
1452 RTF_PREF(pref);
1312 1453
1313 rtmsg.rtmsg_ifindex = dev->ifindex; 1454 rtmsg.rtmsg_ifindex = dev->ifindex;
1314 1455
@@ -1326,8 +1467,6 @@ restart:
1326 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { 1467 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
1327 dst_hold(&rt->u.dst); 1468 dst_hold(&rt->u.dst);
1328 1469
1329 rt6_reset_dflt_pointer(NULL);
1330
1331 read_unlock_bh(&rt6_lock); 1470 read_unlock_bh(&rt6_lock);
1332 1471
1333 ip6_del_rt(rt, NULL, NULL, NULL); 1472 ip6_del_rt(rt, NULL, NULL, NULL);
@@ -1738,11 +1877,10 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
1738 /* 1877 /*
1739 * 2. allocate and initialize walker. 1878 * 2. allocate and initialize walker.
1740 */ 1879 */
1741 w = kmalloc(sizeof(*w), GFP_ATOMIC); 1880 w = kzalloc(sizeof(*w), GFP_ATOMIC);
1742 if (w == NULL) 1881 if (w == NULL)
1743 return -ENOMEM; 1882 return -ENOMEM;
1744 RT6_TRACE("dump<%p", w); 1883 RT6_TRACE("dump<%p", w);
1745 memset(w, 0, sizeof(*w));
1746 w->root = &ip6_routing_table; 1884 w->root = &ip6_routing_table;
1747 w->func = fib6_dump_node; 1885 w->func = fib6_dump_node;
1748 w->args = &arg; 1886 w->args = &arg;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ca9cf6853755..301eee726b0f 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -987,6 +987,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
987 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen + 987 inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
988 newnp->opt->opt_flen); 988 newnp->opt->opt_flen);
989 989
990 tcp_mtup_init(newsk);
990 tcp_sync_mss(newsk, dst_mtu(dst)); 991 tcp_sync_mss(newsk, dst_mtu(dst));
991 newtp->advmss = dst_metric(dst, RTAX_ADVMSS); 992 newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
992 tcp_initialize_rcv_mss(newsk); 993 tcp_initialize_rcv_mss(newsk);
@@ -1297,18 +1298,21 @@ static int tcp_v6_remember_stamp(struct sock *sk)
1297} 1298}
1298 1299
1299static struct inet_connection_sock_af_ops ipv6_specific = { 1300static struct inet_connection_sock_af_ops ipv6_specific = {
1300 .queue_xmit = inet6_csk_xmit, 1301 .queue_xmit = inet6_csk_xmit,
1301 .send_check = tcp_v6_send_check, 1302 .send_check = tcp_v6_send_check,
1302 .rebuild_header = inet6_sk_rebuild_header, 1303 .rebuild_header = inet6_sk_rebuild_header,
1303 .conn_request = tcp_v6_conn_request, 1304 .conn_request = tcp_v6_conn_request,
1304 .syn_recv_sock = tcp_v6_syn_recv_sock, 1305 .syn_recv_sock = tcp_v6_syn_recv_sock,
1305 .remember_stamp = tcp_v6_remember_stamp, 1306 .remember_stamp = tcp_v6_remember_stamp,
1306 .net_header_len = sizeof(struct ipv6hdr), 1307 .net_header_len = sizeof(struct ipv6hdr),
1307 1308 .setsockopt = ipv6_setsockopt,
1308 .setsockopt = ipv6_setsockopt, 1309 .getsockopt = ipv6_getsockopt,
1309 .getsockopt = ipv6_getsockopt, 1310 .addr2sockaddr = inet6_csk_addr2sockaddr,
1310 .addr2sockaddr = inet6_csk_addr2sockaddr, 1311 .sockaddr_len = sizeof(struct sockaddr_in6),
1311 .sockaddr_len = sizeof(struct sockaddr_in6) 1312#ifdef CONFIG_COMPAT
1313 .compat_setsockopt = compat_ipv6_setsockopt,
1314 .compat_getsockopt = compat_ipv6_getsockopt,
1315#endif
1312}; 1316};
1313 1317
1314/* 1318/*
@@ -1316,22 +1320,23 @@ static struct inet_connection_sock_af_ops ipv6_specific = {
1316 */ 1320 */
1317 1321
1318static struct inet_connection_sock_af_ops ipv6_mapped = { 1322static struct inet_connection_sock_af_ops ipv6_mapped = {
1319 .queue_xmit = ip_queue_xmit, 1323 .queue_xmit = ip_queue_xmit,
1320 .send_check = tcp_v4_send_check, 1324 .send_check = tcp_v4_send_check,
1321 .rebuild_header = inet_sk_rebuild_header, 1325 .rebuild_header = inet_sk_rebuild_header,
1322 .conn_request = tcp_v6_conn_request, 1326 .conn_request = tcp_v6_conn_request,
1323 .syn_recv_sock = tcp_v6_syn_recv_sock, 1327 .syn_recv_sock = tcp_v6_syn_recv_sock,
1324 .remember_stamp = tcp_v4_remember_stamp, 1328 .remember_stamp = tcp_v4_remember_stamp,
1325 .net_header_len = sizeof(struct iphdr), 1329 .net_header_len = sizeof(struct iphdr),
1326 1330 .setsockopt = ipv6_setsockopt,
1327 .setsockopt = ipv6_setsockopt, 1331 .getsockopt = ipv6_getsockopt,
1328 .getsockopt = ipv6_getsockopt, 1332 .addr2sockaddr = inet6_csk_addr2sockaddr,
1329 .addr2sockaddr = inet6_csk_addr2sockaddr, 1333 .sockaddr_len = sizeof(struct sockaddr_in6),
1330 .sockaddr_len = sizeof(struct sockaddr_in6) 1334#ifdef CONFIG_COMPAT
1335 .compat_setsockopt = compat_ipv6_setsockopt,
1336 .compat_getsockopt = compat_ipv6_getsockopt,
1337#endif
1331}; 1338};
1332 1339
1333
1334
1335/* NOTE: A lot of things set to zero explicitly by call to 1340/* NOTE: A lot of things set to zero explicitly by call to
1336 * sk_alloc() so need not be done here. 1341 * sk_alloc() so need not be done here.
1337 */ 1342 */
@@ -1583,6 +1588,10 @@ struct proto tcpv6_prot = {
1583 .obj_size = sizeof(struct tcp6_sock), 1588 .obj_size = sizeof(struct tcp6_sock),
1584 .twsk_prot = &tcp6_timewait_sock_ops, 1589 .twsk_prot = &tcp6_timewait_sock_ops,
1585 .rsk_prot = &tcp6_request_sock_ops, 1590 .rsk_prot = &tcp6_request_sock_ops,
1591#ifdef CONFIG_COMPAT
1592 .compat_setsockopt = compat_tcp_setsockopt,
1593 .compat_getsockopt = compat_tcp_getsockopt,
1594#endif
1586}; 1595};
1587 1596
1588static struct inet6_protocol tcpv6_protocol = { 1597static struct inet6_protocol tcpv6_protocol = {
@@ -1604,21 +1613,12 @@ static struct inet_protosw tcpv6_protosw = {
1604 1613
1605void __init tcpv6_init(void) 1614void __init tcpv6_init(void)
1606{ 1615{
1607 int err;
1608
1609 /* register inet6 protocol */ 1616 /* register inet6 protocol */
1610 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0) 1617 if (inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP) < 0)
1611 printk(KERN_ERR "tcpv6_init: Could not register protocol\n"); 1618 printk(KERN_ERR "tcpv6_init: Could not register protocol\n");
1612 inet6_register_protosw(&tcpv6_protosw); 1619 inet6_register_protosw(&tcpv6_protosw);
1613 1620
1614 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_TCP, &tcp6_socket); 1621 if (inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, SOCK_RAW,
1615 if (err < 0) 1622 IPPROTO_TCP) < 0)
1616 panic("Failed to create the TCPv6 control socket.\n"); 1623 panic("Failed to create the TCPv6 control socket.\n");
1617 tcp6_socket->sk->sk_allocation = GFP_ATOMIC;
1618
1619 /* Unhash it so that IP input processing does not even
1620 * see it, we do not wish this socket to see incoming
1621 * packets.
1622 */
1623 tcp6_socket->sk->sk_prot->unhash(tcp6_socket->sk);
1624} 1624}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index c47648892c04..8d3432a70f3a 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -880,16 +880,13 @@ static int udpv6_destroy_sock(struct sock *sk)
880/* 880/*
881 * Socket option code for UDP 881 * Socket option code for UDP
882 */ 882 */
883static int udpv6_setsockopt(struct sock *sk, int level, int optname, 883static int do_udpv6_setsockopt(struct sock *sk, int level, int optname,
884 char __user *optval, int optlen) 884 char __user *optval, int optlen)
885{ 885{
886 struct udp_sock *up = udp_sk(sk); 886 struct udp_sock *up = udp_sk(sk);
887 int val; 887 int val;
888 int err = 0; 888 int err = 0;
889 889
890 if (level != SOL_UDP)
891 return ipv6_setsockopt(sk, level, optname, optval, optlen);
892
893 if(optlen<sizeof(int)) 890 if(optlen<sizeof(int))
894 return -EINVAL; 891 return -EINVAL;
895 892
@@ -927,15 +924,31 @@ static int udpv6_setsockopt(struct sock *sk, int level, int optname,
927 return err; 924 return err;
928} 925}
929 926
930static int udpv6_getsockopt(struct sock *sk, int level, int optname, 927static int udpv6_setsockopt(struct sock *sk, int level, int optname,
928 char __user *optval, int optlen)
929{
930 if (level != SOL_UDP)
931 return ipv6_setsockopt(sk, level, optname, optval, optlen);
932 return do_udpv6_setsockopt(sk, level, optname, optval, optlen);
933}
934
935#ifdef CONFIG_COMPAT
936static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname,
937 char __user *optval, int optlen)
938{
939 if (level != SOL_UDP)
940 return compat_ipv6_setsockopt(sk, level, optname,
941 optval, optlen);
942 return do_udpv6_setsockopt(sk, level, optname, optval, optlen);
943}
944#endif
945
946static int do_udpv6_getsockopt(struct sock *sk, int level, int optname,
931 char __user *optval, int __user *optlen) 947 char __user *optval, int __user *optlen)
932{ 948{
933 struct udp_sock *up = udp_sk(sk); 949 struct udp_sock *up = udp_sk(sk);
934 int val, len; 950 int val, len;
935 951
936 if (level != SOL_UDP)
937 return ipv6_getsockopt(sk, level, optname, optval, optlen);
938
939 if(get_user(len,optlen)) 952 if(get_user(len,optlen))
940 return -EFAULT; 953 return -EFAULT;
941 954
@@ -964,6 +977,25 @@ static int udpv6_getsockopt(struct sock *sk, int level, int optname,
964 return 0; 977 return 0;
965} 978}
966 979
980static int udpv6_getsockopt(struct sock *sk, int level, int optname,
981 char __user *optval, int __user *optlen)
982{
983 if (level != SOL_UDP)
984 return ipv6_getsockopt(sk, level, optname, optval, optlen);
985 return do_udpv6_getsockopt(sk, level, optname, optval, optlen);
986}
987
988#ifdef CONFIG_COMPAT
989static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
990 char __user *optval, int __user *optlen)
991{
992 if (level != SOL_UDP)
993 return compat_ipv6_getsockopt(sk, level, optname,
994 optval, optlen);
995 return do_udpv6_getsockopt(sk, level, optname, optval, optlen);
996}
997#endif
998
967static struct inet6_protocol udpv6_protocol = { 999static struct inet6_protocol udpv6_protocol = {
968 .handler = udpv6_rcv, 1000 .handler = udpv6_rcv,
969 .err_handler = udpv6_err, 1001 .err_handler = udpv6_err,
@@ -1037,22 +1069,26 @@ void udp6_proc_exit(void) {
1037/* ------------------------------------------------------------------------ */ 1069/* ------------------------------------------------------------------------ */
1038 1070
1039struct proto udpv6_prot = { 1071struct proto udpv6_prot = {
1040 .name = "UDPv6", 1072 .name = "UDPv6",
1041 .owner = THIS_MODULE, 1073 .owner = THIS_MODULE,
1042 .close = udpv6_close, 1074 .close = udpv6_close,
1043 .connect = ip6_datagram_connect, 1075 .connect = ip6_datagram_connect,
1044 .disconnect = udp_disconnect, 1076 .disconnect = udp_disconnect,
1045 .ioctl = udp_ioctl, 1077 .ioctl = udp_ioctl,
1046 .destroy = udpv6_destroy_sock, 1078 .destroy = udpv6_destroy_sock,
1047 .setsockopt = udpv6_setsockopt, 1079 .setsockopt = udpv6_setsockopt,
1048 .getsockopt = udpv6_getsockopt, 1080 .getsockopt = udpv6_getsockopt,
1049 .sendmsg = udpv6_sendmsg, 1081 .sendmsg = udpv6_sendmsg,
1050 .recvmsg = udpv6_recvmsg, 1082 .recvmsg = udpv6_recvmsg,
1051 .backlog_rcv = udpv6_queue_rcv_skb, 1083 .backlog_rcv = udpv6_queue_rcv_skb,
1052 .hash = udp_v6_hash, 1084 .hash = udp_v6_hash,
1053 .unhash = udp_v6_unhash, 1085 .unhash = udp_v6_unhash,
1054 .get_port = udp_v6_get_port, 1086 .get_port = udp_v6_get_port,
1055 .obj_size = sizeof(struct udp6_sock), 1087 .obj_size = sizeof(struct udp6_sock),
1088#ifdef CONFIG_COMPAT
1089 .compat_setsockopt = compat_udpv6_setsockopt,
1090 .compat_getsockopt = compat_udpv6_getsockopt,
1091#endif
1056}; 1092};
1057 1093
1058static struct inet_protosw udpv6_protosw = { 1094static struct inet_protosw udpv6_protosw = {
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 8cfc58b96fc2..08f9abbdf1d7 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -31,6 +31,7 @@
31#include <net/protocol.h> 31#include <net/protocol.h>
32#include <linux/ipv6.h> 32#include <linux/ipv6.h>
33#include <linux/icmpv6.h> 33#include <linux/icmpv6.h>
34#include <linux/mutex.h>
34 35
35#ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG 36#ifdef CONFIG_IPV6_XFRM6_TUNNEL_DEBUG
36# define X6TDEBUG 3 37# define X6TDEBUG 3
@@ -357,19 +358,19 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct xfrm_decap_state *dec
357} 358}
358 359
359static struct xfrm6_tunnel *xfrm6_tunnel_handler; 360static struct xfrm6_tunnel *xfrm6_tunnel_handler;
360static DECLARE_MUTEX(xfrm6_tunnel_sem); 361static DEFINE_MUTEX(xfrm6_tunnel_mutex);
361 362
362int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) 363int xfrm6_tunnel_register(struct xfrm6_tunnel *handler)
363{ 364{
364 int ret; 365 int ret;
365 366
366 down(&xfrm6_tunnel_sem); 367 mutex_lock(&xfrm6_tunnel_mutex);
367 ret = 0; 368 ret = 0;
368 if (xfrm6_tunnel_handler != NULL) 369 if (xfrm6_tunnel_handler != NULL)
369 ret = -EINVAL; 370 ret = -EINVAL;
370 if (!ret) 371 if (!ret)
371 xfrm6_tunnel_handler = handler; 372 xfrm6_tunnel_handler = handler;
372 up(&xfrm6_tunnel_sem); 373 mutex_unlock(&xfrm6_tunnel_mutex);
373 374
374 return ret; 375 return ret;
375} 376}
@@ -380,13 +381,13 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler)
380{ 381{
381 int ret; 382 int ret;
382 383
383 down(&xfrm6_tunnel_sem); 384 mutex_lock(&xfrm6_tunnel_mutex);
384 ret = 0; 385 ret = 0;
385 if (xfrm6_tunnel_handler != handler) 386 if (xfrm6_tunnel_handler != handler)
386 ret = -EINVAL; 387 ret = -EINVAL;
387 if (!ret) 388 if (!ret)
388 xfrm6_tunnel_handler = NULL; 389 xfrm6_tunnel_handler = NULL;
389 up(&xfrm6_tunnel_sem); 390 mutex_unlock(&xfrm6_tunnel_mutex);
390 391
391 synchronize_net(); 392 synchronize_net();
392 393