diff options
-rw-r--r-- | net/bridge/netfilter/ebtables.c | 11 | ||||
-rw-r--r-- | net/ipv6/netfilter/Kconfig | 55 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 1 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 8 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_sync.c | 155 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 5 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_extend.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 16 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 69 | ||||
-rw-r--r-- | net/netfilter/xt_connmark.c | 49 |
10 files changed, 200 insertions, 171 deletions
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 032e0fe45940..28a4c3490359 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c | |||
@@ -1825,13 +1825,14 @@ static int compat_table_info(const struct ebt_table_info *info, | |||
1825 | { | 1825 | { |
1826 | unsigned int size = info->entries_size; | 1826 | unsigned int size = info->entries_size; |
1827 | const void *entries = info->entries; | 1827 | const void *entries = info->entries; |
1828 | int ret; | ||
1829 | 1828 | ||
1830 | newinfo->entries_size = size; | 1829 | newinfo->entries_size = size; |
1831 | 1830 | if (info->nentries) { | |
1832 | ret = xt_compat_init_offsets(NFPROTO_BRIDGE, info->nentries); | 1831 | int ret = xt_compat_init_offsets(NFPROTO_BRIDGE, |
1833 | if (ret) | 1832 | info->nentries); |
1834 | return ret; | 1833 | if (ret) |
1834 | return ret; | ||
1835 | } | ||
1835 | 1836 | ||
1836 | return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info, | 1837 | return EBT_ENTRY_ITERATE(entries, size, compat_calc_entry, info, |
1837 | entries, newinfo); | 1838 | entries, newinfo); |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index ccbfa83e4bb0..ce77bcc2490c 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -48,6 +48,34 @@ config NFT_CHAIN_ROUTE_IPV6 | |||
48 | fields such as the source, destination, flowlabel, hop-limit and | 48 | fields such as the source, destination, flowlabel, hop-limit and |
49 | the packet mark. | 49 | the packet mark. |
50 | 50 | ||
51 | if NF_NAT_IPV6 | ||
52 | |||
53 | config NFT_CHAIN_NAT_IPV6 | ||
54 | tristate "IPv6 nf_tables nat chain support" | ||
55 | help | ||
56 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
57 | chain type is used to perform Network Address Translation (NAT) | ||
58 | packet transformations such as the source, destination address and | ||
59 | source and destination ports. | ||
60 | |||
61 | config NFT_MASQ_IPV6 | ||
62 | tristate "IPv6 masquerade support for nf_tables" | ||
63 | depends on NFT_MASQ | ||
64 | select NF_NAT_MASQUERADE_IPV6 | ||
65 | help | ||
66 | This is the expression that provides IPv4 masquerading support for | ||
67 | nf_tables. | ||
68 | |||
69 | config NFT_REDIR_IPV6 | ||
70 | tristate "IPv6 redirect support for nf_tables" | ||
71 | depends on NFT_REDIR | ||
72 | select NF_NAT_REDIRECT | ||
73 | help | ||
74 | This is the expression that provides IPv4 redirect support for | ||
75 | nf_tables. | ||
76 | |||
77 | endif # NF_NAT_IPV6 | ||
78 | |||
51 | config NFT_REJECT_IPV6 | 79 | config NFT_REJECT_IPV6 |
52 | select NF_REJECT_IPV6 | 80 | select NF_REJECT_IPV6 |
53 | default NFT_REJECT | 81 | default NFT_REJECT |
@@ -107,39 +135,12 @@ config NF_NAT_IPV6 | |||
107 | 135 | ||
108 | if NF_NAT_IPV6 | 136 | if NF_NAT_IPV6 |
109 | 137 | ||
110 | config NFT_CHAIN_NAT_IPV6 | ||
111 | depends on NF_TABLES_IPV6 | ||
112 | tristate "IPv6 nf_tables nat chain support" | ||
113 | help | ||
114 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
115 | chain type is used to perform Network Address Translation (NAT) | ||
116 | packet transformations such as the source, destination address and | ||
117 | source and destination ports. | ||
118 | |||
119 | config NF_NAT_MASQUERADE_IPV6 | 138 | config NF_NAT_MASQUERADE_IPV6 |
120 | tristate "IPv6 masquerade support" | 139 | tristate "IPv6 masquerade support" |
121 | help | 140 | help |
122 | This is the kernel functionality to provide NAT in the masquerade | 141 | This is the kernel functionality to provide NAT in the masquerade |
123 | flavour (automatic source address selection) for IPv6. | 142 | flavour (automatic source address selection) for IPv6. |
124 | 143 | ||
125 | config NFT_MASQ_IPV6 | ||
126 | tristate "IPv6 masquerade support for nf_tables" | ||
127 | depends on NF_TABLES_IPV6 | ||
128 | depends on NFT_MASQ | ||
129 | select NF_NAT_MASQUERADE_IPV6 | ||
130 | help | ||
131 | This is the expression that provides IPv4 masquerading support for | ||
132 | nf_tables. | ||
133 | |||
134 | config NFT_REDIR_IPV6 | ||
135 | tristate "IPv6 redirect support for nf_tables" | ||
136 | depends on NF_TABLES_IPV6 | ||
137 | depends on NFT_REDIR | ||
138 | select NF_NAT_REDIRECT | ||
139 | help | ||
140 | This is the expression that provides IPv4 redirect support for | ||
141 | nf_tables. | ||
142 | |||
143 | endif # NF_NAT_IPV6 | 144 | endif # NF_NAT_IPV6 |
144 | 145 | ||
145 | config IP6_NF_IPTABLES | 146 | config IP6_NF_IPTABLES |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 704b3832dbad..44d8a55e9721 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -594,6 +594,7 @@ config NFT_QUOTA | |||
594 | config NFT_REJECT | 594 | config NFT_REJECT |
595 | default m if NETFILTER_ADVANCED=n | 595 | default m if NETFILTER_ADVANCED=n |
596 | tristate "Netfilter nf_tables reject support" | 596 | tristate "Netfilter nf_tables reject support" |
597 | depends on !NF_TABLES_INET || (IPV6!=m || m) | ||
597 | help | 598 | help |
598 | This option adds the "reject" expression that you can use to | 599 | This option adds the "reject" expression that you can use to |
599 | explicitly deny and notify via TCP reset/ICMP informational errors | 600 | explicitly deny and notify via TCP reset/ICMP informational errors |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 5ebde4b15810..f36098887ad0 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -2384,11 +2384,7 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
2384 | strlcpy(cfg.mcast_ifn, dm->mcast_ifn, | 2384 | strlcpy(cfg.mcast_ifn, dm->mcast_ifn, |
2385 | sizeof(cfg.mcast_ifn)); | 2385 | sizeof(cfg.mcast_ifn)); |
2386 | cfg.syncid = dm->syncid; | 2386 | cfg.syncid = dm->syncid; |
2387 | rtnl_lock(); | ||
2388 | mutex_lock(&ipvs->sync_mutex); | ||
2389 | ret = start_sync_thread(ipvs, &cfg, dm->state); | 2387 | ret = start_sync_thread(ipvs, &cfg, dm->state); |
2390 | mutex_unlock(&ipvs->sync_mutex); | ||
2391 | rtnl_unlock(); | ||
2392 | } else { | 2388 | } else { |
2393 | mutex_lock(&ipvs->sync_mutex); | 2389 | mutex_lock(&ipvs->sync_mutex); |
2394 | ret = stop_sync_thread(ipvs, dm->state); | 2390 | ret = stop_sync_thread(ipvs, dm->state); |
@@ -3481,12 +3477,8 @@ static int ip_vs_genl_new_daemon(struct netns_ipvs *ipvs, struct nlattr **attrs) | |||
3481 | if (ipvs->mixed_address_family_dests > 0) | 3477 | if (ipvs->mixed_address_family_dests > 0) |
3482 | return -EINVAL; | 3478 | return -EINVAL; |
3483 | 3479 | ||
3484 | rtnl_lock(); | ||
3485 | mutex_lock(&ipvs->sync_mutex); | ||
3486 | ret = start_sync_thread(ipvs, &c, | 3480 | ret = start_sync_thread(ipvs, &c, |
3487 | nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE])); | 3481 | nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE])); |
3488 | mutex_unlock(&ipvs->sync_mutex); | ||
3489 | rtnl_unlock(); | ||
3490 | return ret; | 3482 | return ret; |
3491 | } | 3483 | } |
3492 | 3484 | ||
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index fbaf3bd05b2e..001501e25625 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/kthread.h> | 49 | #include <linux/kthread.h> |
50 | #include <linux/wait.h> | 50 | #include <linux/wait.h> |
51 | #include <linux/kernel.h> | 51 | #include <linux/kernel.h> |
52 | #include <linux/sched/signal.h> | ||
52 | 53 | ||
53 | #include <asm/unaligned.h> /* Used for ntoh_seq and hton_seq */ | 54 | #include <asm/unaligned.h> /* Used for ntoh_seq and hton_seq */ |
54 | 55 | ||
@@ -1360,15 +1361,9 @@ static void set_mcast_pmtudisc(struct sock *sk, int val) | |||
1360 | /* | 1361 | /* |
1361 | * Specifiy default interface for outgoing multicasts | 1362 | * Specifiy default interface for outgoing multicasts |
1362 | */ | 1363 | */ |
1363 | static int set_mcast_if(struct sock *sk, char *ifname) | 1364 | static int set_mcast_if(struct sock *sk, struct net_device *dev) |
1364 | { | 1365 | { |
1365 | struct net_device *dev; | ||
1366 | struct inet_sock *inet = inet_sk(sk); | 1366 | struct inet_sock *inet = inet_sk(sk); |
1367 | struct net *net = sock_net(sk); | ||
1368 | |||
1369 | dev = __dev_get_by_name(net, ifname); | ||
1370 | if (!dev) | ||
1371 | return -ENODEV; | ||
1372 | 1367 | ||
1373 | if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) | 1368 | if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) |
1374 | return -EINVAL; | 1369 | return -EINVAL; |
@@ -1396,19 +1391,14 @@ static int set_mcast_if(struct sock *sk, char *ifname) | |||
1396 | * in the in_addr structure passed in as a parameter. | 1391 | * in the in_addr structure passed in as a parameter. |
1397 | */ | 1392 | */ |
1398 | static int | 1393 | static int |
1399 | join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) | 1394 | join_mcast_group(struct sock *sk, struct in_addr *addr, struct net_device *dev) |
1400 | { | 1395 | { |
1401 | struct net *net = sock_net(sk); | ||
1402 | struct ip_mreqn mreq; | 1396 | struct ip_mreqn mreq; |
1403 | struct net_device *dev; | ||
1404 | int ret; | 1397 | int ret; |
1405 | 1398 | ||
1406 | memset(&mreq, 0, sizeof(mreq)); | 1399 | memset(&mreq, 0, sizeof(mreq)); |
1407 | memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); | 1400 | memcpy(&mreq.imr_multiaddr, addr, sizeof(struct in_addr)); |
1408 | 1401 | ||
1409 | dev = __dev_get_by_name(net, ifname); | ||
1410 | if (!dev) | ||
1411 | return -ENODEV; | ||
1412 | if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) | 1402 | if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) |
1413 | return -EINVAL; | 1403 | return -EINVAL; |
1414 | 1404 | ||
@@ -1423,15 +1413,10 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname) | |||
1423 | 1413 | ||
1424 | #ifdef CONFIG_IP_VS_IPV6 | 1414 | #ifdef CONFIG_IP_VS_IPV6 |
1425 | static int join_mcast_group6(struct sock *sk, struct in6_addr *addr, | 1415 | static int join_mcast_group6(struct sock *sk, struct in6_addr *addr, |
1426 | char *ifname) | 1416 | struct net_device *dev) |
1427 | { | 1417 | { |
1428 | struct net *net = sock_net(sk); | ||
1429 | struct net_device *dev; | ||
1430 | int ret; | 1418 | int ret; |
1431 | 1419 | ||
1432 | dev = __dev_get_by_name(net, ifname); | ||
1433 | if (!dev) | ||
1434 | return -ENODEV; | ||
1435 | if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) | 1420 | if (sk->sk_bound_dev_if && dev->ifindex != sk->sk_bound_dev_if) |
1436 | return -EINVAL; | 1421 | return -EINVAL; |
1437 | 1422 | ||
@@ -1443,24 +1428,18 @@ static int join_mcast_group6(struct sock *sk, struct in6_addr *addr, | |||
1443 | } | 1428 | } |
1444 | #endif | 1429 | #endif |
1445 | 1430 | ||
1446 | static int bind_mcastif_addr(struct socket *sock, char *ifname) | 1431 | static int bind_mcastif_addr(struct socket *sock, struct net_device *dev) |
1447 | { | 1432 | { |
1448 | struct net *net = sock_net(sock->sk); | ||
1449 | struct net_device *dev; | ||
1450 | __be32 addr; | 1433 | __be32 addr; |
1451 | struct sockaddr_in sin; | 1434 | struct sockaddr_in sin; |
1452 | 1435 | ||
1453 | dev = __dev_get_by_name(net, ifname); | ||
1454 | if (!dev) | ||
1455 | return -ENODEV; | ||
1456 | |||
1457 | addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); | 1436 | addr = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); |
1458 | if (!addr) | 1437 | if (!addr) |
1459 | pr_err("You probably need to specify IP address on " | 1438 | pr_err("You probably need to specify IP address on " |
1460 | "multicast interface.\n"); | 1439 | "multicast interface.\n"); |
1461 | 1440 | ||
1462 | IP_VS_DBG(7, "binding socket with (%s) %pI4\n", | 1441 | IP_VS_DBG(7, "binding socket with (%s) %pI4\n", |
1463 | ifname, &addr); | 1442 | dev->name, &addr); |
1464 | 1443 | ||
1465 | /* Now bind the socket with the address of multicast interface */ | 1444 | /* Now bind the socket with the address of multicast interface */ |
1466 | sin.sin_family = AF_INET; | 1445 | sin.sin_family = AF_INET; |
@@ -1493,7 +1472,8 @@ static void get_mcast_sockaddr(union ipvs_sockaddr *sa, int *salen, | |||
1493 | /* | 1472 | /* |
1494 | * Set up sending multicast socket over UDP | 1473 | * Set up sending multicast socket over UDP |
1495 | */ | 1474 | */ |
1496 | static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) | 1475 | static int make_send_sock(struct netns_ipvs *ipvs, int id, |
1476 | struct net_device *dev, struct socket **sock_ret) | ||
1497 | { | 1477 | { |
1498 | /* multicast addr */ | 1478 | /* multicast addr */ |
1499 | union ipvs_sockaddr mcast_addr; | 1479 | union ipvs_sockaddr mcast_addr; |
@@ -1505,9 +1485,10 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) | |||
1505 | IPPROTO_UDP, &sock); | 1485 | IPPROTO_UDP, &sock); |
1506 | if (result < 0) { | 1486 | if (result < 0) { |
1507 | pr_err("Error during creation of socket; terminating\n"); | 1487 | pr_err("Error during creation of socket; terminating\n"); |
1508 | return ERR_PTR(result); | 1488 | goto error; |
1509 | } | 1489 | } |
1510 | result = set_mcast_if(sock->sk, ipvs->mcfg.mcast_ifn); | 1490 | *sock_ret = sock; |
1491 | result = set_mcast_if(sock->sk, dev); | ||
1511 | if (result < 0) { | 1492 | if (result < 0) { |
1512 | pr_err("Error setting outbound mcast interface\n"); | 1493 | pr_err("Error setting outbound mcast interface\n"); |
1513 | goto error; | 1494 | goto error; |
@@ -1522,7 +1503,7 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) | |||
1522 | set_sock_size(sock->sk, 1, result); | 1503 | set_sock_size(sock->sk, 1, result); |
1523 | 1504 | ||
1524 | if (AF_INET == ipvs->mcfg.mcast_af) | 1505 | if (AF_INET == ipvs->mcfg.mcast_af) |
1525 | result = bind_mcastif_addr(sock, ipvs->mcfg.mcast_ifn); | 1506 | result = bind_mcastif_addr(sock, dev); |
1526 | else | 1507 | else |
1527 | result = 0; | 1508 | result = 0; |
1528 | if (result < 0) { | 1509 | if (result < 0) { |
@@ -1538,19 +1519,18 @@ static struct socket *make_send_sock(struct netns_ipvs *ipvs, int id) | |||
1538 | goto error; | 1519 | goto error; |
1539 | } | 1520 | } |
1540 | 1521 | ||
1541 | return sock; | 1522 | return 0; |
1542 | 1523 | ||
1543 | error: | 1524 | error: |
1544 | sock_release(sock); | 1525 | return result; |
1545 | return ERR_PTR(result); | ||
1546 | } | 1526 | } |
1547 | 1527 | ||
1548 | 1528 | ||
1549 | /* | 1529 | /* |
1550 | * Set up receiving multicast socket over UDP | 1530 | * Set up receiving multicast socket over UDP |
1551 | */ | 1531 | */ |
1552 | static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, | 1532 | static int make_receive_sock(struct netns_ipvs *ipvs, int id, |
1553 | int ifindex) | 1533 | struct net_device *dev, struct socket **sock_ret) |
1554 | { | 1534 | { |
1555 | /* multicast addr */ | 1535 | /* multicast addr */ |
1556 | union ipvs_sockaddr mcast_addr; | 1536 | union ipvs_sockaddr mcast_addr; |
@@ -1562,8 +1542,9 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, | |||
1562 | IPPROTO_UDP, &sock); | 1542 | IPPROTO_UDP, &sock); |
1563 | if (result < 0) { | 1543 | if (result < 0) { |
1564 | pr_err("Error during creation of socket; terminating\n"); | 1544 | pr_err("Error during creation of socket; terminating\n"); |
1565 | return ERR_PTR(result); | 1545 | goto error; |
1566 | } | 1546 | } |
1547 | *sock_ret = sock; | ||
1567 | /* it is equivalent to the REUSEADDR option in user-space */ | 1548 | /* it is equivalent to the REUSEADDR option in user-space */ |
1568 | sock->sk->sk_reuse = SK_CAN_REUSE; | 1549 | sock->sk->sk_reuse = SK_CAN_REUSE; |
1569 | result = sysctl_sync_sock_size(ipvs); | 1550 | result = sysctl_sync_sock_size(ipvs); |
@@ -1571,7 +1552,7 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, | |||
1571 | set_sock_size(sock->sk, 0, result); | 1552 | set_sock_size(sock->sk, 0, result); |
1572 | 1553 | ||
1573 | get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id); | 1554 | get_mcast_sockaddr(&mcast_addr, &salen, &ipvs->bcfg, id); |
1574 | sock->sk->sk_bound_dev_if = ifindex; | 1555 | sock->sk->sk_bound_dev_if = dev->ifindex; |
1575 | result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen); | 1556 | result = sock->ops->bind(sock, (struct sockaddr *)&mcast_addr, salen); |
1576 | if (result < 0) { | 1557 | if (result < 0) { |
1577 | pr_err("Error binding to the multicast addr\n"); | 1558 | pr_err("Error binding to the multicast addr\n"); |
@@ -1582,21 +1563,20 @@ static struct socket *make_receive_sock(struct netns_ipvs *ipvs, int id, | |||
1582 | #ifdef CONFIG_IP_VS_IPV6 | 1563 | #ifdef CONFIG_IP_VS_IPV6 |
1583 | if (ipvs->bcfg.mcast_af == AF_INET6) | 1564 | if (ipvs->bcfg.mcast_af == AF_INET6) |
1584 | result = join_mcast_group6(sock->sk, &mcast_addr.in6.sin6_addr, | 1565 | result = join_mcast_group6(sock->sk, &mcast_addr.in6.sin6_addr, |
1585 | ipvs->bcfg.mcast_ifn); | 1566 | dev); |
1586 | else | 1567 | else |
1587 | #endif | 1568 | #endif |
1588 | result = join_mcast_group(sock->sk, &mcast_addr.in.sin_addr, | 1569 | result = join_mcast_group(sock->sk, &mcast_addr.in.sin_addr, |
1589 | ipvs->bcfg.mcast_ifn); | 1570 | dev); |
1590 | if (result < 0) { | 1571 | if (result < 0) { |
1591 | pr_err("Error joining to the multicast group\n"); | 1572 | pr_err("Error joining to the multicast group\n"); |
1592 | goto error; | 1573 | goto error; |
1593 | } | 1574 | } |
1594 | 1575 | ||
1595 | return sock; | 1576 | return 0; |
1596 | 1577 | ||
1597 | error: | 1578 | error: |
1598 | sock_release(sock); | 1579 | return result; |
1599 | return ERR_PTR(result); | ||
1600 | } | 1580 | } |
1601 | 1581 | ||
1602 | 1582 | ||
@@ -1778,13 +1758,12 @@ static int sync_thread_backup(void *data) | |||
1778 | int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, | 1758 | int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, |
1779 | int state) | 1759 | int state) |
1780 | { | 1760 | { |
1781 | struct ip_vs_sync_thread_data *tinfo; | 1761 | struct ip_vs_sync_thread_data *tinfo = NULL; |
1782 | struct task_struct **array = NULL, *task; | 1762 | struct task_struct **array = NULL, *task; |
1783 | struct socket *sock; | ||
1784 | struct net_device *dev; | 1763 | struct net_device *dev; |
1785 | char *name; | 1764 | char *name; |
1786 | int (*threadfn)(void *data); | 1765 | int (*threadfn)(void *data); |
1787 | int id, count, hlen; | 1766 | int id = 0, count, hlen; |
1788 | int result = -ENOMEM; | 1767 | int result = -ENOMEM; |
1789 | u16 mtu, min_mtu; | 1768 | u16 mtu, min_mtu; |
1790 | 1769 | ||
@@ -1792,6 +1771,18 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, | |||
1792 | IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n", | 1771 | IP_VS_DBG(7, "Each ip_vs_sync_conn entry needs %zd bytes\n", |
1793 | sizeof(struct ip_vs_sync_conn_v0)); | 1772 | sizeof(struct ip_vs_sync_conn_v0)); |
1794 | 1773 | ||
1774 | /* Do not hold one mutex and then to block on another */ | ||
1775 | for (;;) { | ||
1776 | rtnl_lock(); | ||
1777 | if (mutex_trylock(&ipvs->sync_mutex)) | ||
1778 | break; | ||
1779 | rtnl_unlock(); | ||
1780 | mutex_lock(&ipvs->sync_mutex); | ||
1781 | if (rtnl_trylock()) | ||
1782 | break; | ||
1783 | mutex_unlock(&ipvs->sync_mutex); | ||
1784 | } | ||
1785 | |||
1795 | if (!ipvs->sync_state) { | 1786 | if (!ipvs->sync_state) { |
1796 | count = clamp(sysctl_sync_ports(ipvs), 1, IPVS_SYNC_PORTS_MAX); | 1787 | count = clamp(sysctl_sync_ports(ipvs), 1, IPVS_SYNC_PORTS_MAX); |
1797 | ipvs->threads_mask = count - 1; | 1788 | ipvs->threads_mask = count - 1; |
@@ -1810,7 +1801,8 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, | |||
1810 | dev = __dev_get_by_name(ipvs->net, c->mcast_ifn); | 1801 | dev = __dev_get_by_name(ipvs->net, c->mcast_ifn); |
1811 | if (!dev) { | 1802 | if (!dev) { |
1812 | pr_err("Unknown mcast interface: %s\n", c->mcast_ifn); | 1803 | pr_err("Unknown mcast interface: %s\n", c->mcast_ifn); |
1813 | return -ENODEV; | 1804 | result = -ENODEV; |
1805 | goto out_early; | ||
1814 | } | 1806 | } |
1815 | hlen = (AF_INET6 == c->mcast_af) ? | 1807 | hlen = (AF_INET6 == c->mcast_af) ? |
1816 | sizeof(struct ipv6hdr) + sizeof(struct udphdr) : | 1808 | sizeof(struct ipv6hdr) + sizeof(struct udphdr) : |
@@ -1827,26 +1819,30 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, | |||
1827 | c->sync_maxlen = mtu - hlen; | 1819 | c->sync_maxlen = mtu - hlen; |
1828 | 1820 | ||
1829 | if (state == IP_VS_STATE_MASTER) { | 1821 | if (state == IP_VS_STATE_MASTER) { |
1822 | result = -EEXIST; | ||
1830 | if (ipvs->ms) | 1823 | if (ipvs->ms) |
1831 | return -EEXIST; | 1824 | goto out_early; |
1832 | 1825 | ||
1833 | ipvs->mcfg = *c; | 1826 | ipvs->mcfg = *c; |
1834 | name = "ipvs-m:%d:%d"; | 1827 | name = "ipvs-m:%d:%d"; |
1835 | threadfn = sync_thread_master; | 1828 | threadfn = sync_thread_master; |
1836 | } else if (state == IP_VS_STATE_BACKUP) { | 1829 | } else if (state == IP_VS_STATE_BACKUP) { |
1830 | result = -EEXIST; | ||
1837 | if (ipvs->backup_threads) | 1831 | if (ipvs->backup_threads) |
1838 | return -EEXIST; | 1832 | goto out_early; |
1839 | 1833 | ||
1840 | ipvs->bcfg = *c; | 1834 | ipvs->bcfg = *c; |
1841 | name = "ipvs-b:%d:%d"; | 1835 | name = "ipvs-b:%d:%d"; |
1842 | threadfn = sync_thread_backup; | 1836 | threadfn = sync_thread_backup; |
1843 | } else { | 1837 | } else { |
1844 | return -EINVAL; | 1838 | result = -EINVAL; |
1839 | goto out_early; | ||
1845 | } | 1840 | } |
1846 | 1841 | ||
1847 | if (state == IP_VS_STATE_MASTER) { | 1842 | if (state == IP_VS_STATE_MASTER) { |
1848 | struct ipvs_master_sync_state *ms; | 1843 | struct ipvs_master_sync_state *ms; |
1849 | 1844 | ||
1845 | result = -ENOMEM; | ||
1850 | ipvs->ms = kcalloc(count, sizeof(ipvs->ms[0]), GFP_KERNEL); | 1846 | ipvs->ms = kcalloc(count, sizeof(ipvs->ms[0]), GFP_KERNEL); |
1851 | if (!ipvs->ms) | 1847 | if (!ipvs->ms) |
1852 | goto out; | 1848 | goto out; |
@@ -1862,39 +1858,38 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, | |||
1862 | } else { | 1858 | } else { |
1863 | array = kcalloc(count, sizeof(struct task_struct *), | 1859 | array = kcalloc(count, sizeof(struct task_struct *), |
1864 | GFP_KERNEL); | 1860 | GFP_KERNEL); |
1861 | result = -ENOMEM; | ||
1865 | if (!array) | 1862 | if (!array) |
1866 | goto out; | 1863 | goto out; |
1867 | } | 1864 | } |
1868 | 1865 | ||
1869 | tinfo = NULL; | ||
1870 | for (id = 0; id < count; id++) { | 1866 | for (id = 0; id < count; id++) { |
1871 | if (state == IP_VS_STATE_MASTER) | 1867 | result = -ENOMEM; |
1872 | sock = make_send_sock(ipvs, id); | ||
1873 | else | ||
1874 | sock = make_receive_sock(ipvs, id, dev->ifindex); | ||
1875 | if (IS_ERR(sock)) { | ||
1876 | result = PTR_ERR(sock); | ||
1877 | goto outtinfo; | ||
1878 | } | ||
1879 | tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL); | 1868 | tinfo = kmalloc(sizeof(*tinfo), GFP_KERNEL); |
1880 | if (!tinfo) | 1869 | if (!tinfo) |
1881 | goto outsocket; | 1870 | goto out; |
1882 | tinfo->ipvs = ipvs; | 1871 | tinfo->ipvs = ipvs; |
1883 | tinfo->sock = sock; | 1872 | tinfo->sock = NULL; |
1884 | if (state == IP_VS_STATE_BACKUP) { | 1873 | if (state == IP_VS_STATE_BACKUP) { |
1885 | tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen, | 1874 | tinfo->buf = kmalloc(ipvs->bcfg.sync_maxlen, |
1886 | GFP_KERNEL); | 1875 | GFP_KERNEL); |
1887 | if (!tinfo->buf) | 1876 | if (!tinfo->buf) |
1888 | goto outtinfo; | 1877 | goto out; |
1889 | } else { | 1878 | } else { |
1890 | tinfo->buf = NULL; | 1879 | tinfo->buf = NULL; |
1891 | } | 1880 | } |
1892 | tinfo->id = id; | 1881 | tinfo->id = id; |
1882 | if (state == IP_VS_STATE_MASTER) | ||
1883 | result = make_send_sock(ipvs, id, dev, &tinfo->sock); | ||
1884 | else | ||
1885 | result = make_receive_sock(ipvs, id, dev, &tinfo->sock); | ||
1886 | if (result < 0) | ||
1887 | goto out; | ||
1893 | 1888 | ||
1894 | task = kthread_run(threadfn, tinfo, name, ipvs->gen, id); | 1889 | task = kthread_run(threadfn, tinfo, name, ipvs->gen, id); |
1895 | if (IS_ERR(task)) { | 1890 | if (IS_ERR(task)) { |
1896 | result = PTR_ERR(task); | 1891 | result = PTR_ERR(task); |
1897 | goto outtinfo; | 1892 | goto out; |
1898 | } | 1893 | } |
1899 | tinfo = NULL; | 1894 | tinfo = NULL; |
1900 | if (state == IP_VS_STATE_MASTER) | 1895 | if (state == IP_VS_STATE_MASTER) |
@@ -1911,20 +1906,20 @@ int start_sync_thread(struct netns_ipvs *ipvs, struct ipvs_sync_daemon_cfg *c, | |||
1911 | ipvs->sync_state |= state; | 1906 | ipvs->sync_state |= state; |
1912 | spin_unlock_bh(&ipvs->sync_buff_lock); | 1907 | spin_unlock_bh(&ipvs->sync_buff_lock); |
1913 | 1908 | ||
1909 | mutex_unlock(&ipvs->sync_mutex); | ||
1910 | rtnl_unlock(); | ||
1911 | |||
1914 | /* increase the module use count */ | 1912 | /* increase the module use count */ |
1915 | ip_vs_use_count_inc(); | 1913 | ip_vs_use_count_inc(); |
1916 | 1914 | ||
1917 | return 0; | 1915 | return 0; |
1918 | 1916 | ||
1919 | outsocket: | 1917 | out: |
1920 | sock_release(sock); | 1918 | /* We do not need RTNL lock anymore, release it here so that |
1921 | 1919 | * sock_release below and in the kthreads can use rtnl_lock | |
1922 | outtinfo: | 1920 | * to leave the mcast group. |
1923 | if (tinfo) { | 1921 | */ |
1924 | sock_release(tinfo->sock); | 1922 | rtnl_unlock(); |
1925 | kfree(tinfo->buf); | ||
1926 | kfree(tinfo); | ||
1927 | } | ||
1928 | count = id; | 1923 | count = id; |
1929 | while (count-- > 0) { | 1924 | while (count-- > 0) { |
1930 | if (state == IP_VS_STATE_MASTER) | 1925 | if (state == IP_VS_STATE_MASTER) |
@@ -1932,13 +1927,23 @@ outtinfo: | |||
1932 | else | 1927 | else |
1933 | kthread_stop(array[count]); | 1928 | kthread_stop(array[count]); |
1934 | } | 1929 | } |
1935 | kfree(array); | ||
1936 | |||
1937 | out: | ||
1938 | if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) { | 1930 | if (!(ipvs->sync_state & IP_VS_STATE_MASTER)) { |
1939 | kfree(ipvs->ms); | 1931 | kfree(ipvs->ms); |
1940 | ipvs->ms = NULL; | 1932 | ipvs->ms = NULL; |
1941 | } | 1933 | } |
1934 | mutex_unlock(&ipvs->sync_mutex); | ||
1935 | if (tinfo) { | ||
1936 | if (tinfo->sock) | ||
1937 | sock_release(tinfo->sock); | ||
1938 | kfree(tinfo->buf); | ||
1939 | kfree(tinfo); | ||
1940 | } | ||
1941 | kfree(array); | ||
1942 | return result; | ||
1943 | |||
1944 | out_early: | ||
1945 | mutex_unlock(&ipvs->sync_mutex); | ||
1946 | rtnl_unlock(); | ||
1942 | return result; | 1947 | return result; |
1943 | } | 1948 | } |
1944 | 1949 | ||
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 8ef21d9f9a00..4b2b3d53acfc 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -252,7 +252,7 @@ static inline int expect_clash(const struct nf_conntrack_expect *a, | |||
252 | static inline int expect_matches(const struct nf_conntrack_expect *a, | 252 | static inline int expect_matches(const struct nf_conntrack_expect *a, |
253 | const struct nf_conntrack_expect *b) | 253 | const struct nf_conntrack_expect *b) |
254 | { | 254 | { |
255 | return a->master == b->master && a->class == b->class && | 255 | return a->master == b->master && |
256 | nf_ct_tuple_equal(&a->tuple, &b->tuple) && | 256 | nf_ct_tuple_equal(&a->tuple, &b->tuple) && |
257 | nf_ct_tuple_mask_equal(&a->mask, &b->mask) && | 257 | nf_ct_tuple_mask_equal(&a->mask, &b->mask) && |
258 | net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) && | 258 | net_eq(nf_ct_net(a->master), nf_ct_net(b->master)) && |
@@ -421,6 +421,9 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | |||
421 | h = nf_ct_expect_dst_hash(net, &expect->tuple); | 421 | h = nf_ct_expect_dst_hash(net, &expect->tuple); |
422 | hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { | 422 | hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { |
423 | if (expect_matches(i, expect)) { | 423 | if (expect_matches(i, expect)) { |
424 | if (i->class != expect->class) | ||
425 | return -EALREADY; | ||
426 | |||
424 | if (nf_ct_remove_expect(i)) | 427 | if (nf_ct_remove_expect(i)) |
425 | break; | 428 | break; |
426 | } else if (expect_clash(i, expect)) { | 429 | } else if (expect_clash(i, expect)) { |
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 9fe0ddc333fb..277bbfe26478 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/kmemleak.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/mutex.h> | 14 | #include <linux/mutex.h> |
14 | #include <linux/rcupdate.h> | 15 | #include <linux/rcupdate.h> |
@@ -71,6 +72,7 @@ void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) | |||
71 | rcu_read_unlock(); | 72 | rcu_read_unlock(); |
72 | 73 | ||
73 | alloc = max(newlen, NF_CT_EXT_PREALLOC); | 74 | alloc = max(newlen, NF_CT_EXT_PREALLOC); |
75 | kmemleak_not_leak(old); | ||
74 | new = __krealloc(old, alloc, gfp); | 76 | new = __krealloc(old, alloc, gfp); |
75 | if (!new) | 77 | if (!new) |
76 | return NULL; | 78 | return NULL; |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 4dbb5bad4363..908e51e2dc2b 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -938,11 +938,19 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, | |||
938 | datalen, rtp_exp, rtcp_exp, | 938 | datalen, rtp_exp, rtcp_exp, |
939 | mediaoff, medialen, daddr); | 939 | mediaoff, medialen, daddr); |
940 | else { | 940 | else { |
941 | if (nf_ct_expect_related(rtp_exp) == 0) { | 941 | /* -EALREADY handling works around end-points that send |
942 | if (nf_ct_expect_related(rtcp_exp) != 0) | 942 | * SDP messages with identical port but different media type, |
943 | nf_ct_unexpect_related(rtp_exp); | 943 | * we pretend expectation was set up. |
944 | else | 944 | */ |
945 | int errp = nf_ct_expect_related(rtp_exp); | ||
946 | |||
947 | if (errp == 0 || errp == -EALREADY) { | ||
948 | int errcp = nf_ct_expect_related(rtcp_exp); | ||
949 | |||
950 | if (errcp == 0 || errcp == -EALREADY) | ||
945 | ret = NF_ACCEPT; | 951 | ret = NF_ACCEPT; |
952 | else if (errp == 0) | ||
953 | nf_ct_unexpect_related(rtp_exp); | ||
946 | } | 954 | } |
947 | } | 955 | } |
948 | nf_ct_expect_put(rtcp_exp); | 956 | nf_ct_expect_put(rtcp_exp); |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 9134cc429ad4..04d4e3772584 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -2361,41 +2361,46 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk, | |||
2361 | } | 2361 | } |
2362 | 2362 | ||
2363 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | 2363 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { |
2364 | if (nft_is_active_next(net, old_rule)) { | 2364 | if (!nft_is_active_next(net, old_rule)) { |
2365 | trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE, | ||
2366 | old_rule); | ||
2367 | if (trans == NULL) { | ||
2368 | err = -ENOMEM; | ||
2369 | goto err2; | ||
2370 | } | ||
2371 | nft_deactivate_next(net, old_rule); | ||
2372 | chain->use--; | ||
2373 | list_add_tail_rcu(&rule->list, &old_rule->list); | ||
2374 | } else { | ||
2375 | err = -ENOENT; | 2365 | err = -ENOENT; |
2376 | goto err2; | 2366 | goto err2; |
2377 | } | 2367 | } |
2378 | } else if (nlh->nlmsg_flags & NLM_F_APPEND) | 2368 | trans = nft_trans_rule_add(&ctx, NFT_MSG_DELRULE, |
2379 | if (old_rule) | 2369 | old_rule); |
2380 | list_add_rcu(&rule->list, &old_rule->list); | 2370 | if (trans == NULL) { |
2381 | else | 2371 | err = -ENOMEM; |
2382 | list_add_tail_rcu(&rule->list, &chain->rules); | 2372 | goto err2; |
2383 | else { | 2373 | } |
2384 | if (old_rule) | 2374 | nft_deactivate_next(net, old_rule); |
2385 | list_add_tail_rcu(&rule->list, &old_rule->list); | 2375 | chain->use--; |
2386 | else | ||
2387 | list_add_rcu(&rule->list, &chain->rules); | ||
2388 | } | ||
2389 | 2376 | ||
2390 | if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { | 2377 | if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { |
2391 | err = -ENOMEM; | 2378 | err = -ENOMEM; |
2392 | goto err3; | 2379 | goto err2; |
2380 | } | ||
2381 | |||
2382 | list_add_tail_rcu(&rule->list, &old_rule->list); | ||
2383 | } else { | ||
2384 | if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { | ||
2385 | err = -ENOMEM; | ||
2386 | goto err2; | ||
2387 | } | ||
2388 | |||
2389 | if (nlh->nlmsg_flags & NLM_F_APPEND) { | ||
2390 | if (old_rule) | ||
2391 | list_add_rcu(&rule->list, &old_rule->list); | ||
2392 | else | ||
2393 | list_add_tail_rcu(&rule->list, &chain->rules); | ||
2394 | } else { | ||
2395 | if (old_rule) | ||
2396 | list_add_tail_rcu(&rule->list, &old_rule->list); | ||
2397 | else | ||
2398 | list_add_rcu(&rule->list, &chain->rules); | ||
2399 | } | ||
2393 | } | 2400 | } |
2394 | chain->use++; | 2401 | chain->use++; |
2395 | return 0; | 2402 | return 0; |
2396 | 2403 | ||
2397 | err3: | ||
2398 | list_del_rcu(&rule->list); | ||
2399 | err2: | 2404 | err2: |
2400 | nf_tables_rule_destroy(&ctx, rule); | 2405 | nf_tables_rule_destroy(&ctx, rule); |
2401 | err1: | 2406 | err1: |
@@ -3207,18 +3212,20 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, | |||
3207 | 3212 | ||
3208 | err = ops->init(set, &desc, nla); | 3213 | err = ops->init(set, &desc, nla); |
3209 | if (err < 0) | 3214 | if (err < 0) |
3210 | goto err2; | 3215 | goto err3; |
3211 | 3216 | ||
3212 | err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set); | 3217 | err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set); |
3213 | if (err < 0) | 3218 | if (err < 0) |
3214 | goto err3; | 3219 | goto err4; |
3215 | 3220 | ||
3216 | list_add_tail_rcu(&set->list, &table->sets); | 3221 | list_add_tail_rcu(&set->list, &table->sets); |
3217 | table->use++; | 3222 | table->use++; |
3218 | return 0; | 3223 | return 0; |
3219 | 3224 | ||
3220 | err3: | 3225 | err4: |
3221 | ops->destroy(set); | 3226 | ops->destroy(set); |
3227 | err3: | ||
3228 | kfree(set->name); | ||
3222 | err2: | 3229 | err2: |
3223 | kvfree(set); | 3230 | kvfree(set); |
3224 | err1: | 3231 | err1: |
@@ -5738,7 +5745,7 @@ static void nft_chain_commit_update(struct nft_trans *trans) | |||
5738 | struct nft_base_chain *basechain; | 5745 | struct nft_base_chain *basechain; |
5739 | 5746 | ||
5740 | if (nft_trans_chain_name(trans)) | 5747 | if (nft_trans_chain_name(trans)) |
5741 | strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans)); | 5748 | swap(trans->ctx.chain->name, nft_trans_chain_name(trans)); |
5742 | 5749 | ||
5743 | if (!nft_is_base_chain(trans->ctx.chain)) | 5750 | if (!nft_is_base_chain(trans->ctx.chain)) |
5744 | return; | 5751 | return; |
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 773da82190dc..94df000abb92 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c | |||
@@ -36,11 +36,10 @@ MODULE_ALIAS("ipt_connmark"); | |||
36 | MODULE_ALIAS("ip6t_connmark"); | 36 | MODULE_ALIAS("ip6t_connmark"); |
37 | 37 | ||
38 | static unsigned int | 38 | static unsigned int |
39 | connmark_tg_shift(struct sk_buff *skb, | 39 | connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) |
40 | const struct xt_connmark_tginfo1 *info, | ||
41 | u8 shift_bits, u8 shift_dir) | ||
42 | { | 40 | { |
43 | enum ip_conntrack_info ctinfo; | 41 | enum ip_conntrack_info ctinfo; |
42 | u_int32_t new_targetmark; | ||
44 | struct nf_conn *ct; | 43 | struct nf_conn *ct; |
45 | u_int32_t newmark; | 44 | u_int32_t newmark; |
46 | 45 | ||
@@ -51,34 +50,39 @@ connmark_tg_shift(struct sk_buff *skb, | |||
51 | switch (info->mode) { | 50 | switch (info->mode) { |
52 | case XT_CONNMARK_SET: | 51 | case XT_CONNMARK_SET: |
53 | newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; | 52 | newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; |
54 | if (shift_dir == D_SHIFT_RIGHT) | 53 | if (info->shift_dir == D_SHIFT_RIGHT) |
55 | newmark >>= shift_bits; | 54 | newmark >>= info->shift_bits; |
56 | else | 55 | else |
57 | newmark <<= shift_bits; | 56 | newmark <<= info->shift_bits; |
57 | |||
58 | if (ct->mark != newmark) { | 58 | if (ct->mark != newmark) { |
59 | ct->mark = newmark; | 59 | ct->mark = newmark; |
60 | nf_conntrack_event_cache(IPCT_MARK, ct); | 60 | nf_conntrack_event_cache(IPCT_MARK, ct); |
61 | } | 61 | } |
62 | break; | 62 | break; |
63 | case XT_CONNMARK_SAVE: | 63 | case XT_CONNMARK_SAVE: |
64 | newmark = (ct->mark & ~info->ctmask) ^ | 64 | new_targetmark = (skb->mark & info->nfmask); |
65 | (skb->mark & info->nfmask); | 65 | if (info->shift_dir == D_SHIFT_RIGHT) |
66 | if (shift_dir == D_SHIFT_RIGHT) | 66 | new_targetmark >>= info->shift_bits; |
67 | newmark >>= shift_bits; | ||
68 | else | 67 | else |
69 | newmark <<= shift_bits; | 68 | new_targetmark <<= info->shift_bits; |
69 | |||
70 | newmark = (ct->mark & ~info->ctmask) ^ | ||
71 | new_targetmark; | ||
70 | if (ct->mark != newmark) { | 72 | if (ct->mark != newmark) { |
71 | ct->mark = newmark; | 73 | ct->mark = newmark; |
72 | nf_conntrack_event_cache(IPCT_MARK, ct); | 74 | nf_conntrack_event_cache(IPCT_MARK, ct); |
73 | } | 75 | } |
74 | break; | 76 | break; |
75 | case XT_CONNMARK_RESTORE: | 77 | case XT_CONNMARK_RESTORE: |
76 | newmark = (skb->mark & ~info->nfmask) ^ | 78 | new_targetmark = (ct->mark & info->ctmask); |
77 | (ct->mark & info->ctmask); | 79 | if (info->shift_dir == D_SHIFT_RIGHT) |
78 | if (shift_dir == D_SHIFT_RIGHT) | 80 | new_targetmark >>= info->shift_bits; |
79 | newmark >>= shift_bits; | ||
80 | else | 81 | else |
81 | newmark <<= shift_bits; | 82 | new_targetmark <<= info->shift_bits; |
83 | |||
84 | newmark = (skb->mark & ~info->nfmask) ^ | ||
85 | new_targetmark; | ||
82 | skb->mark = newmark; | 86 | skb->mark = newmark; |
83 | break; | 87 | break; |
84 | } | 88 | } |
@@ -89,8 +93,14 @@ static unsigned int | |||
89 | connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) | 93 | connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) |
90 | { | 94 | { |
91 | const struct xt_connmark_tginfo1 *info = par->targinfo; | 95 | const struct xt_connmark_tginfo1 *info = par->targinfo; |
92 | 96 | const struct xt_connmark_tginfo2 info2 = { | |
93 | return connmark_tg_shift(skb, info, 0, 0); | 97 | .ctmark = info->ctmark, |
98 | .ctmask = info->ctmask, | ||
99 | .nfmask = info->nfmask, | ||
100 | .mode = info->mode, | ||
101 | }; | ||
102 | |||
103 | return connmark_tg_shift(skb, &info2); | ||
94 | } | 104 | } |
95 | 105 | ||
96 | static unsigned int | 106 | static unsigned int |
@@ -98,8 +108,7 @@ connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) | |||
98 | { | 108 | { |
99 | const struct xt_connmark_tginfo2 *info = par->targinfo; | 109 | const struct xt_connmark_tginfo2 *info = par->targinfo; |
100 | 110 | ||
101 | return connmark_tg_shift(skb, (const struct xt_connmark_tginfo1 *)info, | 111 | return connmark_tg_shift(skb, info); |
102 | info->shift_bits, info->shift_dir); | ||
103 | } | 112 | } |
104 | 113 | ||
105 | static int connmark_tg_check(const struct xt_tgchk_param *par) | 114 | static int connmark_tg_check(const struct xt_tgchk_param *par) |