diff options
Diffstat (limited to 'net')
63 files changed, 905 insertions, 469 deletions
diff --git a/net/Kconfig b/net/Kconfig index b3250944cde9..e24fa0873f32 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -32,7 +32,7 @@ config WANT_COMPAT_NETLINK_MESSAGES | |||
32 | config COMPAT_NETLINK_MESSAGES | 32 | config COMPAT_NETLINK_MESSAGES |
33 | def_bool y | 33 | def_bool y |
34 | depends on COMPAT | 34 | depends on COMPAT |
35 | depends on WIRELESS_EXT || WANT_COMPAT_NETLINK_MESSAGES | 35 | depends on WEXT_CORE || WANT_COMPAT_NETLINK_MESSAGES |
36 | help | 36 | help |
37 | This option makes it possible to send different netlink messages | 37 | This option makes it possible to send different netlink messages |
38 | to tasks depending on whether the task is a compat task or not. To | 38 | to tasks depending on whether the task is a compat task or not. To |
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 075c435ad22d..cf09fe591fc2 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
23 | #include "br_private.h" | 23 | #include "br_private.h" |
24 | 24 | ||
25 | /* net device transmit always called with no BH (preempt_disabled) */ | 25 | /* net device transmit always called with BH disabled */ |
26 | netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | 26 | netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) |
27 | { | 27 | { |
28 | struct net_bridge *br = netdev_priv(dev); | 28 | struct net_bridge *br = netdev_priv(dev); |
@@ -48,13 +48,16 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
48 | skb_reset_mac_header(skb); | 48 | skb_reset_mac_header(skb); |
49 | skb_pull(skb, ETH_HLEN); | 49 | skb_pull(skb, ETH_HLEN); |
50 | 50 | ||
51 | rcu_read_lock(); | ||
51 | if (is_multicast_ether_addr(dest)) { | 52 | if (is_multicast_ether_addr(dest)) { |
52 | if (unlikely(netpoll_tx_running(dev))) { | 53 | if (unlikely(netpoll_tx_running(dev))) { |
53 | br_flood_deliver(br, skb); | 54 | br_flood_deliver(br, skb); |
54 | goto out; | 55 | goto out; |
55 | } | 56 | } |
56 | if (br_multicast_rcv(br, NULL, skb)) | 57 | if (br_multicast_rcv(br, NULL, skb)) { |
58 | kfree_skb(skb); | ||
57 | goto out; | 59 | goto out; |
60 | } | ||
58 | 61 | ||
59 | mdst = br_mdb_get(br, skb); | 62 | mdst = br_mdb_get(br, skb); |
60 | if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) | 63 | if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) |
@@ -67,6 +70,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
67 | br_flood_deliver(br, skb); | 70 | br_flood_deliver(br, skb); |
68 | 71 | ||
69 | out: | 72 | out: |
73 | rcu_read_unlock(); | ||
70 | return NETDEV_TX_OK; | 74 | return NETDEV_TX_OK; |
71 | } | 75 | } |
72 | 76 | ||
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index a744296fc675..90512ccfd3e9 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -214,7 +214,7 @@ void br_fdb_delete_by_port(struct net_bridge *br, | |||
214 | spin_unlock_bh(&br->hash_lock); | 214 | spin_unlock_bh(&br->hash_lock); |
215 | } | 215 | } |
216 | 216 | ||
217 | /* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */ | 217 | /* No locking or refcounting, assumes caller has rcu_read_lock */ |
218 | struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, | 218 | struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, |
219 | const unsigned char *addr) | 219 | const unsigned char *addr) |
220 | { | 220 | { |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 5fc1c5b1c360..826cd5221536 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -39,7 +39,7 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
39 | netif_receive_skb); | 39 | netif_receive_skb); |
40 | } | 40 | } |
41 | 41 | ||
42 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 42 | /* note: already called with rcu_read_lock */ |
43 | int br_handle_frame_finish(struct sk_buff *skb) | 43 | int br_handle_frame_finish(struct sk_buff *skb) |
44 | { | 44 | { |
45 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 45 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
@@ -110,7 +110,7 @@ drop: | |||
110 | goto out; | 110 | goto out; |
111 | } | 111 | } |
112 | 112 | ||
113 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 113 | /* note: already called with rcu_read_lock */ |
114 | static int br_handle_local_finish(struct sk_buff *skb) | 114 | static int br_handle_local_finish(struct sk_buff *skb) |
115 | { | 115 | { |
116 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); | 116 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
@@ -133,8 +133,7 @@ static inline int is_link_local(const unsigned char *dest) | |||
133 | 133 | ||
134 | /* | 134 | /* |
135 | * Return NULL if skb is handled | 135 | * Return NULL if skb is handled |
136 | * note: already called with rcu_read_lock (preempt_disabled) from | 136 | * note: already called with rcu_read_lock |
137 | * netif_receive_skb | ||
138 | */ | 137 | */ |
139 | struct sk_buff *br_handle_frame(struct sk_buff *skb) | 138 | struct sk_buff *br_handle_frame(struct sk_buff *skb) |
140 | { | 139 | { |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 85afcdab4921..eb5b256ffc88 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -1728,13 +1728,9 @@ unlock: | |||
1728 | int br_multicast_toggle(struct net_bridge *br, unsigned long val) | 1728 | int br_multicast_toggle(struct net_bridge *br, unsigned long val) |
1729 | { | 1729 | { |
1730 | struct net_bridge_port *port; | 1730 | struct net_bridge_port *port; |
1731 | int err = -ENOENT; | 1731 | int err = 0; |
1732 | 1732 | ||
1733 | spin_lock(&br->multicast_lock); | 1733 | spin_lock(&br->multicast_lock); |
1734 | if (!netif_running(br->dev)) | ||
1735 | goto unlock; | ||
1736 | |||
1737 | err = 0; | ||
1738 | if (br->multicast_disabled == !val) | 1734 | if (br->multicast_disabled == !val) |
1739 | goto unlock; | 1735 | goto unlock; |
1740 | 1736 | ||
@@ -1742,6 +1738,9 @@ int br_multicast_toggle(struct net_bridge *br, unsigned long val) | |||
1742 | if (br->multicast_disabled) | 1738 | if (br->multicast_disabled) |
1743 | goto unlock; | 1739 | goto unlock; |
1744 | 1740 | ||
1741 | if (!netif_running(br->dev)) | ||
1742 | goto unlock; | ||
1743 | |||
1745 | if (br->mdb) { | 1744 | if (br->mdb) { |
1746 | if (br->mdb->old) { | 1745 | if (br->mdb->old) { |
1747 | err = -EEXIST; | 1746 | err = -EEXIST; |
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 70aecb48fb69..35cf27087b56 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -131,7 +131,7 @@ void br_send_tcn_bpdu(struct net_bridge_port *p) | |||
131 | /* | 131 | /* |
132 | * Called from llc. | 132 | * Called from llc. |
133 | * | 133 | * |
134 | * NO locks, but rcu_read_lock (preempt_disabled) | 134 | * NO locks, but rcu_read_lock |
135 | */ | 135 | */ |
136 | void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, | 136 | void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb, |
137 | struct net_device *dev) | 137 | struct net_device *dev) |
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index 4b04d25b6a3f..eb1602022ac0 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c | |||
@@ -193,7 +193,7 @@ out: | |||
193 | 193 | ||
194 | static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt) | 194 | static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt) |
195 | { | 195 | { |
196 | caif_assert(!cfpkt_getlen(pkt) < rfml->fragment_size); | 196 | caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size); |
197 | 197 | ||
198 | /* Add info for MUX-layer to route the packet out. */ | 198 | /* Add info for MUX-layer to route the packet out. */ |
199 | cfpkt_info(pkt)->channel_id = rfml->serv.layer.id; | 199 | cfpkt_info(pkt)->channel_id = rfml->serv.layer.id; |
diff --git a/net/can/raw.c b/net/can/raw.c index ccfe633eec8e..a10e3338f084 100644 --- a/net/can/raw.c +++ b/net/can/raw.c | |||
@@ -650,6 +650,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
650 | err = sock_tx_timestamp(msg, sk, skb_tx(skb)); | 650 | err = sock_tx_timestamp(msg, sk, skb_tx(skb)); |
651 | if (err < 0) | 651 | if (err < 0) |
652 | goto free_skb; | 652 | goto free_skb; |
653 | |||
654 | /* to be able to check the received tx sock reference in raw_rcv() */ | ||
655 | skb_tx(skb)->prevent_sk_orphan = 1; | ||
656 | |||
653 | skb->dev = dev; | 657 | skb->dev = dev; |
654 | skb->sk = sk; | 658 | skb->sk = sk; |
655 | 659 | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 6e1b4370781c..e1c1cdcc2bb0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -101,8 +101,6 @@ | |||
101 | #include <linux/proc_fs.h> | 101 | #include <linux/proc_fs.h> |
102 | #include <linux/seq_file.h> | 102 | #include <linux/seq_file.h> |
103 | #include <linux/stat.h> | 103 | #include <linux/stat.h> |
104 | #include <linux/if_bridge.h> | ||
105 | #include <linux/if_macvlan.h> | ||
106 | #include <net/dst.h> | 104 | #include <net/dst.h> |
107 | #include <net/pkt_sched.h> | 105 | #include <net/pkt_sched.h> |
108 | #include <net/checksum.h> | 106 | #include <net/checksum.h> |
@@ -1484,6 +1482,7 @@ static inline void net_timestamp_check(struct sk_buff *skb) | |||
1484 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) | 1482 | int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) |
1485 | { | 1483 | { |
1486 | skb_orphan(skb); | 1484 | skb_orphan(skb); |
1485 | nf_reset(skb); | ||
1487 | 1486 | ||
1488 | if (!(dev->flags & IFF_UP) || | 1487 | if (!(dev->flags & IFF_UP) || |
1489 | (skb->len > (dev->mtu + dev->hard_header_len))) { | 1488 | (skb->len > (dev->mtu + dev->hard_header_len))) { |
@@ -1592,9 +1591,7 @@ EXPORT_SYMBOL(__netif_schedule); | |||
1592 | 1591 | ||
1593 | void dev_kfree_skb_irq(struct sk_buff *skb) | 1592 | void dev_kfree_skb_irq(struct sk_buff *skb) |
1594 | { | 1593 | { |
1595 | if (!skb->destructor) | 1594 | if (atomic_dec_and_test(&skb->users)) { |
1596 | dev_kfree_skb(skb); | ||
1597 | else if (atomic_dec_and_test(&skb->users)) { | ||
1598 | struct softnet_data *sd; | 1595 | struct softnet_data *sd; |
1599 | unsigned long flags; | 1596 | unsigned long flags; |
1600 | 1597 | ||
@@ -2645,10 +2642,10 @@ static int ing_filter(struct sk_buff *skb) | |||
2645 | int result = TC_ACT_OK; | 2642 | int result = TC_ACT_OK; |
2646 | struct Qdisc *q; | 2643 | struct Qdisc *q; |
2647 | 2644 | ||
2648 | if (MAX_RED_LOOP < ttl++) { | 2645 | if (unlikely(MAX_RED_LOOP < ttl++)) { |
2649 | printk(KERN_WARNING | 2646 | if (net_ratelimit()) |
2650 | "Redir loop detected Dropping packet (%d->%d)\n", | 2647 | pr_warning( "Redir loop detected Dropping packet (%d->%d)\n", |
2651 | skb->skb_iif, dev->ifindex); | 2648 | skb->skb_iif, dev->ifindex); |
2652 | return TC_ACT_SHOT; | 2649 | return TC_ACT_SHOT; |
2653 | } | 2650 | } |
2654 | 2651 | ||
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index 646ef3bc7200..36e603c78ce9 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c | |||
@@ -347,9 +347,9 @@ static struct notifier_block dropmon_net_notifier = { | |||
347 | 347 | ||
348 | static int __init init_net_drop_monitor(void) | 348 | static int __init init_net_drop_monitor(void) |
349 | { | 349 | { |
350 | int cpu; | ||
351 | int rc, i, ret; | ||
352 | struct per_cpu_dm_data *data; | 350 | struct per_cpu_dm_data *data; |
351 | int cpu, rc; | ||
352 | |||
353 | printk(KERN_INFO "Initalizing network drop monitor service\n"); | 353 | printk(KERN_INFO "Initalizing network drop monitor service\n"); |
354 | 354 | ||
355 | if (sizeof(void *) > 8) { | 355 | if (sizeof(void *) > 8) { |
@@ -357,21 +357,12 @@ static int __init init_net_drop_monitor(void) | |||
357 | return -ENOSPC; | 357 | return -ENOSPC; |
358 | } | 358 | } |
359 | 359 | ||
360 | if (genl_register_family(&net_drop_monitor_family) < 0) { | 360 | rc = genl_register_family_with_ops(&net_drop_monitor_family, |
361 | dropmon_ops, | ||
362 | ARRAY_SIZE(dropmon_ops)); | ||
363 | if (rc) { | ||
361 | printk(KERN_ERR "Could not create drop monitor netlink family\n"); | 364 | printk(KERN_ERR "Could not create drop monitor netlink family\n"); |
362 | return -EFAULT; | 365 | return rc; |
363 | } | ||
364 | |||
365 | rc = -EFAULT; | ||
366 | |||
367 | for (i = 0; i < ARRAY_SIZE(dropmon_ops); i++) { | ||
368 | ret = genl_register_ops(&net_drop_monitor_family, | ||
369 | &dropmon_ops[i]); | ||
370 | if (ret) { | ||
371 | printk(KERN_CRIT "Failed to register operation %d\n", | ||
372 | dropmon_ops[i].cmd); | ||
373 | goto out_unreg; | ||
374 | } | ||
375 | } | 366 | } |
376 | 367 | ||
377 | rc = register_netdevice_notifier(&dropmon_net_notifier); | 368 | rc = register_netdevice_notifier(&dropmon_net_notifier); |
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index d2b596537d41..af4dfbadf2a0 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c | |||
@@ -95,6 +95,7 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, | |||
95 | } | 95 | } |
96 | 96 | ||
97 | NETDEVICE_SHOW(dev_id, fmt_hex); | 97 | NETDEVICE_SHOW(dev_id, fmt_hex); |
98 | NETDEVICE_SHOW(addr_assign_type, fmt_dec); | ||
98 | NETDEVICE_SHOW(addr_len, fmt_dec); | 99 | NETDEVICE_SHOW(addr_len, fmt_dec); |
99 | NETDEVICE_SHOW(iflink, fmt_dec); | 100 | NETDEVICE_SHOW(iflink, fmt_dec); |
100 | NETDEVICE_SHOW(ifindex, fmt_dec); | 101 | NETDEVICE_SHOW(ifindex, fmt_dec); |
@@ -295,6 +296,7 @@ static ssize_t show_ifalias(struct device *dev, | |||
295 | } | 296 | } |
296 | 297 | ||
297 | static struct device_attribute net_class_attributes[] = { | 298 | static struct device_attribute net_class_attributes[] = { |
299 | __ATTR(addr_assign_type, S_IRUGO, show_addr_assign_type, NULL), | ||
298 | __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), | 300 | __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), |
299 | __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), | 301 | __ATTR(dev_id, S_IRUGO, show_dev_id, NULL), |
300 | __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), | 302 | __ATTR(ifalias, S_IRUGO | S_IWUSR, show_ifalias, store_ifalias), |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index c2b7a8bed8f6..537e01afd81b 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -49,6 +49,7 @@ static atomic_t trapped; | |||
49 | (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ | 49 | (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ |
50 | sizeof(struct iphdr) + sizeof(struct ethhdr)) | 50 | sizeof(struct iphdr) + sizeof(struct ethhdr)) |
51 | 51 | ||
52 | static void zap_completion_queue(void); | ||
52 | static void arp_reply(struct sk_buff *skb); | 53 | static void arp_reply(struct sk_buff *skb); |
53 | 54 | ||
54 | static unsigned int carrier_timeout = 4; | 55 | static unsigned int carrier_timeout = 4; |
@@ -196,6 +197,7 @@ void netpoll_poll_dev(struct net_device *dev) | |||
196 | 197 | ||
197 | service_arp_queue(dev->npinfo); | 198 | service_arp_queue(dev->npinfo); |
198 | 199 | ||
200 | zap_completion_queue(); | ||
199 | } | 201 | } |
200 | EXPORT_SYMBOL(netpoll_poll_dev); | 202 | EXPORT_SYMBOL(netpoll_poll_dev); |
201 | 203 | ||
@@ -221,11 +223,40 @@ static void refill_skbs(void) | |||
221 | spin_unlock_irqrestore(&skb_pool.lock, flags); | 223 | spin_unlock_irqrestore(&skb_pool.lock, flags); |
222 | } | 224 | } |
223 | 225 | ||
226 | static void zap_completion_queue(void) | ||
227 | { | ||
228 | unsigned long flags; | ||
229 | struct softnet_data *sd = &get_cpu_var(softnet_data); | ||
230 | |||
231 | if (sd->completion_queue) { | ||
232 | struct sk_buff *clist; | ||
233 | |||
234 | local_irq_save(flags); | ||
235 | clist = sd->completion_queue; | ||
236 | sd->completion_queue = NULL; | ||
237 | local_irq_restore(flags); | ||
238 | |||
239 | while (clist != NULL) { | ||
240 | struct sk_buff *skb = clist; | ||
241 | clist = clist->next; | ||
242 | if (skb->destructor) { | ||
243 | atomic_inc(&skb->users); | ||
244 | dev_kfree_skb_any(skb); /* put this one back */ | ||
245 | } else { | ||
246 | __kfree_skb(skb); | ||
247 | } | ||
248 | } | ||
249 | } | ||
250 | |||
251 | put_cpu_var(softnet_data); | ||
252 | } | ||
253 | |||
224 | static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve) | 254 | static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve) |
225 | { | 255 | { |
226 | int count = 0; | 256 | int count = 0; |
227 | struct sk_buff *skb; | 257 | struct sk_buff *skb; |
228 | 258 | ||
259 | zap_completion_queue(); | ||
229 | refill_skbs(); | 260 | refill_skbs(); |
230 | repeat: | 261 | repeat: |
231 | 262 | ||
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 24a19debda1b..10a1ea72010d 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -1434,18 +1434,12 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1434 | i += len; | 1434 | i += len; |
1435 | 1435 | ||
1436 | for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { | 1436 | for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { |
1437 | if (*v >= '0' && *v <= '9') { | 1437 | int value; |
1438 | *m *= 16; | 1438 | |
1439 | *m += *v - '0'; | 1439 | value = hex_to_bin(*v); |
1440 | } | 1440 | if (value >= 0) |
1441 | if (*v >= 'A' && *v <= 'F') { | 1441 | *m = *m * 16 + value; |
1442 | *m *= 16; | 1442 | |
1443 | *m += *v - 'A' + 10; | ||
1444 | } | ||
1445 | if (*v >= 'a' && *v <= 'f') { | ||
1446 | *m *= 16; | ||
1447 | *m += *v - 'a' + 10; | ||
1448 | } | ||
1449 | if (*v == ':') { | 1443 | if (*v == ':') { |
1450 | m++; | 1444 | m++; |
1451 | *m = 0; | 1445 | *m = 0; |
@@ -1476,18 +1470,12 @@ static ssize_t pktgen_if_write(struct file *file, | |||
1476 | i += len; | 1470 | i += len; |
1477 | 1471 | ||
1478 | for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { | 1472 | for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { |
1479 | if (*v >= '0' && *v <= '9') { | 1473 | int value; |
1480 | *m *= 16; | 1474 | |
1481 | *m += *v - '0'; | 1475 | value = hex_to_bin(*v); |
1482 | } | 1476 | if (value >= 0) |
1483 | if (*v >= 'A' && *v <= 'F') { | 1477 | *m = *m * 16 + value; |
1484 | *m *= 16; | 1478 | |
1485 | *m += *v - 'A' + 10; | ||
1486 | } | ||
1487 | if (*v >= 'a' && *v <= 'f') { | ||
1488 | *m *= 16; | ||
1489 | *m += *v - 'a' + 10; | ||
1490 | } | ||
1491 | if (*v == ':') { | 1479 | if (*v == ':') { |
1492 | m++; | 1480 | m++; |
1493 | *m = 0; | 1481 | *m = 0; |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 76d33ca5f037..3a2513f0d0c3 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -817,7 +817,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
817 | memcpy(data + nhead, skb->head, skb->tail - skb->head); | 817 | memcpy(data + nhead, skb->head, skb->tail - skb->head); |
818 | #endif | 818 | #endif |
819 | memcpy(data + size, skb_end_pointer(skb), | 819 | memcpy(data + size, skb_end_pointer(skb), |
820 | sizeof(struct skb_shared_info)); | 820 | offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags])); |
821 | 821 | ||
822 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) | 822 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) |
823 | get_page(skb_shinfo(skb)->frags[i].page); | 823 | get_page(skb_shinfo(skb)->frags[i].page); |
@@ -843,7 +843,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
843 | skb->network_header += off; | 843 | skb->network_header += off; |
844 | if (skb_mac_header_was_set(skb)) | 844 | if (skb_mac_header_was_set(skb)) |
845 | skb->mac_header += off; | 845 | skb->mac_header += off; |
846 | skb->csum_start += nhead; | 846 | /* Only adjust this if it actually is csum_start rather than csum */ |
847 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
848 | skb->csum_start += nhead; | ||
847 | skb->cloned = 0; | 849 | skb->cloned = 0; |
848 | skb->hdr_len = 0; | 850 | skb->hdr_len = 0; |
849 | skb->nohdr = 0; | 851 | skb->nohdr = 0; |
@@ -930,7 +932,8 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, | |||
930 | copy_skb_header(n, skb); | 932 | copy_skb_header(n, skb); |
931 | 933 | ||
932 | off = newheadroom - oldheadroom; | 934 | off = newheadroom - oldheadroom; |
933 | n->csum_start += off; | 935 | if (n->ip_summed == CHECKSUM_PARTIAL) |
936 | n->csum_start += off; | ||
934 | #ifdef NET_SKBUFF_DATA_USES_OFFSET | 937 | #ifdef NET_SKBUFF_DATA_USES_OFFSET |
935 | n->transport_header += off; | 938 | n->transport_header += off; |
936 | n->network_header += off; | 939 | n->network_header += off; |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 6652bd9da676..04b69896df5f 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -446,7 +446,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
446 | int ptr; | 446 | int ptr; |
447 | struct net_device *dev; | 447 | struct net_device *dev; |
448 | struct sk_buff *skb2; | 448 | struct sk_buff *skb2; |
449 | unsigned int mtu, hlen, left, len, ll_rs, pad; | 449 | unsigned int mtu, hlen, left, len, ll_rs; |
450 | int offset; | 450 | int offset; |
451 | __be16 not_last_frag; | 451 | __be16 not_last_frag; |
452 | struct rtable *rt = skb_rtable(skb); | 452 | struct rtable *rt = skb_rtable(skb); |
@@ -585,9 +585,7 @@ slow_path: | |||
585 | /* for bridged IP traffic encapsulated inside f.e. a vlan header, | 585 | /* for bridged IP traffic encapsulated inside f.e. a vlan header, |
586 | * we need to make room for the encapsulating header | 586 | * we need to make room for the encapsulating header |
587 | */ | 587 | */ |
588 | pad = nf_bridge_pad(skb); | 588 | ll_rs = LL_RESERVED_SPACE_EXTRA(rt->dst.dev, nf_bridge_pad(skb)); |
589 | ll_rs = LL_RESERVED_SPACE_EXTRA(rt->dst.dev, pad); | ||
590 | mtu -= pad; | ||
591 | 589 | ||
592 | /* | 590 | /* |
593 | * Fragment the datagram. | 591 | * Fragment the datagram. |
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 16c0ba0a2728..6bccba31d132 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -283,16 +283,13 @@ unsigned int arpt_do_table(struct sk_buff *skb, | |||
283 | arp = arp_hdr(skb); | 283 | arp = arp_hdr(skb); |
284 | do { | 284 | do { |
285 | const struct arpt_entry_target *t; | 285 | const struct arpt_entry_target *t; |
286 | int hdr_len; | ||
287 | 286 | ||
288 | if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { | 287 | if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) { |
289 | e = arpt_next_entry(e); | 288 | e = arpt_next_entry(e); |
290 | continue; | 289 | continue; |
291 | } | 290 | } |
292 | 291 | ||
293 | hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) + | 292 | ADD_COUNTER(e->counters, arp_hdr_len(skb->dev), 1); |
294 | (2 * skb->dev->addr_len); | ||
295 | ADD_COUNTER(e->counters, hdr_len, 1); | ||
296 | 293 | ||
297 | t = arpt_get_target_c(e); | 294 | t = arpt_get_target_c(e); |
298 | 295 | ||
@@ -713,7 +710,7 @@ static void get_counters(const struct xt_table_info *t, | |||
713 | struct arpt_entry *iter; | 710 | struct arpt_entry *iter; |
714 | unsigned int cpu; | 711 | unsigned int cpu; |
715 | unsigned int i; | 712 | unsigned int i; |
716 | unsigned int curcpu; | 713 | unsigned int curcpu = get_cpu(); |
717 | 714 | ||
718 | /* Instead of clearing (by a previous call to memset()) | 715 | /* Instead of clearing (by a previous call to memset()) |
719 | * the counters and using adds, we set the counters | 716 | * the counters and using adds, we set the counters |
@@ -723,14 +720,16 @@ static void get_counters(const struct xt_table_info *t, | |||
723 | * if new softirq were to run and call ipt_do_table | 720 | * if new softirq were to run and call ipt_do_table |
724 | */ | 721 | */ |
725 | local_bh_disable(); | 722 | local_bh_disable(); |
726 | curcpu = smp_processor_id(); | ||
727 | |||
728 | i = 0; | 723 | i = 0; |
729 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { | 724 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
730 | SET_COUNTER(counters[i], iter->counters.bcnt, | 725 | SET_COUNTER(counters[i], iter->counters.bcnt, |
731 | iter->counters.pcnt); | 726 | iter->counters.pcnt); |
732 | ++i; | 727 | ++i; |
733 | } | 728 | } |
729 | local_bh_enable(); | ||
730 | /* Processing counters from other cpus, we can let bottom half enabled, | ||
731 | * (preemption is disabled) | ||
732 | */ | ||
734 | 733 | ||
735 | for_each_possible_cpu(cpu) { | 734 | for_each_possible_cpu(cpu) { |
736 | if (cpu == curcpu) | 735 | if (cpu == curcpu) |
@@ -744,7 +743,7 @@ static void get_counters(const struct xt_table_info *t, | |||
744 | } | 743 | } |
745 | xt_info_wrunlock(cpu); | 744 | xt_info_wrunlock(cpu); |
746 | } | 745 | } |
747 | local_bh_enable(); | 746 | put_cpu(); |
748 | } | 747 | } |
749 | 748 | ||
750 | static struct xt_counters *alloc_counters(const struct xt_table *table) | 749 | static struct xt_counters *alloc_counters(const struct xt_table *table) |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index b38c11810c65..c439721b165a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -364,7 +364,7 @@ ipt_do_table(struct sk_buff *skb, | |||
364 | goto no_match; | 364 | goto no_match; |
365 | } | 365 | } |
366 | 366 | ||
367 | ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1); | 367 | ADD_COUNTER(e->counters, skb->len, 1); |
368 | 368 | ||
369 | t = ipt_get_target(e); | 369 | t = ipt_get_target(e); |
370 | IP_NF_ASSERT(t->u.kernel.target); | 370 | IP_NF_ASSERT(t->u.kernel.target); |
@@ -884,7 +884,7 @@ get_counters(const struct xt_table_info *t, | |||
884 | struct ipt_entry *iter; | 884 | struct ipt_entry *iter; |
885 | unsigned int cpu; | 885 | unsigned int cpu; |
886 | unsigned int i; | 886 | unsigned int i; |
887 | unsigned int curcpu; | 887 | unsigned int curcpu = get_cpu(); |
888 | 888 | ||
889 | /* Instead of clearing (by a previous call to memset()) | 889 | /* Instead of clearing (by a previous call to memset()) |
890 | * the counters and using adds, we set the counters | 890 | * the counters and using adds, we set the counters |
@@ -894,14 +894,16 @@ get_counters(const struct xt_table_info *t, | |||
894 | * if new softirq were to run and call ipt_do_table | 894 | * if new softirq were to run and call ipt_do_table |
895 | */ | 895 | */ |
896 | local_bh_disable(); | 896 | local_bh_disable(); |
897 | curcpu = smp_processor_id(); | ||
898 | |||
899 | i = 0; | 897 | i = 0; |
900 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { | 898 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
901 | SET_COUNTER(counters[i], iter->counters.bcnt, | 899 | SET_COUNTER(counters[i], iter->counters.bcnt, |
902 | iter->counters.pcnt); | 900 | iter->counters.pcnt); |
903 | ++i; | 901 | ++i; |
904 | } | 902 | } |
903 | local_bh_enable(); | ||
904 | /* Processing counters from other cpus, we can let bottom half enabled, | ||
905 | * (preemption is disabled) | ||
906 | */ | ||
905 | 907 | ||
906 | for_each_possible_cpu(cpu) { | 908 | for_each_possible_cpu(cpu) { |
907 | if (cpu == curcpu) | 909 | if (cpu == curcpu) |
@@ -915,7 +917,7 @@ get_counters(const struct xt_table_info *t, | |||
915 | } | 917 | } |
916 | xt_info_wrunlock(cpu); | 918 | xt_info_wrunlock(cpu); |
917 | } | 919 | } |
918 | local_bh_enable(); | 920 | put_cpu(); |
919 | } | 921 | } |
920 | 922 | ||
921 | static struct xt_counters *alloc_counters(const struct xt_table *table) | 923 | static struct xt_counters *alloc_counters(const struct xt_table *table) |
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 64d0875f5192..3a43cf36db87 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -469,7 +469,7 @@ struct arp_payload { | |||
469 | __be32 src_ip; | 469 | __be32 src_ip; |
470 | u_int8_t dst_hw[ETH_ALEN]; | 470 | u_int8_t dst_hw[ETH_ALEN]; |
471 | __be32 dst_ip; | 471 | __be32 dst_ip; |
472 | } __attribute__ ((packed)); | 472 | } __packed; |
473 | 473 | ||
474 | #ifdef DEBUG | 474 | #ifdef DEBUG |
475 | static void arp_print(struct arp_payload *payload) | 475 | static void arp_print(struct arp_payload *payload) |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index bbbd2736c549..b254dafaf429 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -95,10 +95,11 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
95 | } | 95 | } |
96 | 96 | ||
97 | tcph->rst = 1; | 97 | tcph->rst = 1; |
98 | tcph->check = tcp_v4_check(sizeof(struct tcphdr), | 98 | tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, |
99 | niph->saddr, niph->daddr, | 99 | niph->daddr, 0); |
100 | csum_partial(tcph, | 100 | nskb->ip_summed = CHECKSUM_PARTIAL; |
101 | sizeof(struct tcphdr), 0)); | 101 | nskb->csum_start = (unsigned char *)tcph - nskb->head; |
102 | nskb->csum_offset = offsetof(struct tcphdr, check); | ||
102 | 103 | ||
103 | addr_type = RTN_UNSPEC; | 104 | addr_type = RTN_UNSPEC; |
104 | if (hook != NF_INET_FORWARD | 105 | if (hook != NF_INET_FORWARD |
@@ -115,7 +116,6 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
115 | goto free_nskb; | 116 | goto free_nskb; |
116 | 117 | ||
117 | niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); | 118 | niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); |
118 | nskb->ip_summed = CHECKSUM_NONE; | ||
119 | 119 | ||
120 | /* "Never happens" */ | 120 | /* "Never happens" */ |
121 | if (nskb->len > dst_mtu(skb_dst(nskb))) | 121 | if (nskb->len > dst_mtu(skb_dst(nskb))) |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index c7719b283ada..8c8632d9b93c 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -261,14 +261,9 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
261 | rcu_read_lock(); | 261 | rcu_read_lock(); |
262 | proto = __nf_nat_proto_find(orig_tuple->dst.protonum); | 262 | proto = __nf_nat_proto_find(orig_tuple->dst.protonum); |
263 | 263 | ||
264 | /* Change protocol info to have some randomization */ | ||
265 | if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { | ||
266 | proto->unique_tuple(tuple, range, maniptype, ct); | ||
267 | goto out; | ||
268 | } | ||
269 | |||
270 | /* Only bother mapping if it's not already in range and unique */ | 264 | /* Only bother mapping if it's not already in range and unique */ |
271 | if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || | 265 | if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM) && |
266 | (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || | ||
272 | proto->in_range(tuple, maniptype, &range->min, &range->max)) && | 267 | proto->in_range(tuple, maniptype, &range->min, &range->max)) && |
273 | !nf_nat_used_tuple(tuple, ct)) | 268 | !nf_nat_used_tuple(tuple, ct)) |
274 | goto out; | 269 | goto out; |
@@ -440,7 +435,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct, | |||
440 | if (!skb_make_writable(skb, hdrlen + sizeof(*inside))) | 435 | if (!skb_make_writable(skb, hdrlen + sizeof(*inside))) |
441 | return 0; | 436 | return 0; |
442 | 437 | ||
443 | inside = (void *)skb->data + ip_hdrlen(skb); | 438 | inside = (void *)skb->data + hdrlen; |
444 | 439 | ||
445 | /* We're actually going to mangle it beyond trivial checksum | 440 | /* We're actually going to mangle it beyond trivial checksum |
446 | adjustment, so make sure the current checksum is correct. */ | 441 | adjustment, so make sure the current checksum is correct. */ |
@@ -470,12 +465,10 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct, | |||
470 | /* rcu_read_lock()ed by nf_hook_slow */ | 465 | /* rcu_read_lock()ed by nf_hook_slow */ |
471 | l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); | 466 | l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol); |
472 | 467 | ||
473 | if (!nf_ct_get_tuple(skb, | 468 | if (!nf_ct_get_tuple(skb, hdrlen + sizeof(struct icmphdr), |
474 | ip_hdrlen(skb) + sizeof(struct icmphdr), | 469 | (hdrlen + |
475 | (ip_hdrlen(skb) + | ||
476 | sizeof(struct icmphdr) + inside->ip.ihl * 4), | 470 | sizeof(struct icmphdr) + inside->ip.ihl * 4), |
477 | (u_int16_t)AF_INET, | 471 | (u_int16_t)AF_INET, inside->ip.protocol, |
478 | inside->ip.protocol, | ||
479 | &inner, l3proto, l4proto)) | 472 | &inner, l3proto, l4proto)) |
480 | return 0; | 473 | return 0; |
481 | 474 | ||
@@ -484,15 +477,13 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct, | |||
484 | pass all hooks (locally-generated ICMP). Consider incoming | 477 | pass all hooks (locally-generated ICMP). Consider incoming |
485 | packet: PREROUTING (DST manip), routing produces ICMP, goes | 478 | packet: PREROUTING (DST manip), routing produces ICMP, goes |
486 | through POSTROUTING (which must correct the DST manip). */ | 479 | through POSTROUTING (which must correct the DST manip). */ |
487 | if (!manip_pkt(inside->ip.protocol, skb, | 480 | if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp), |
488 | ip_hdrlen(skb) + sizeof(inside->icmp), | 481 | &ct->tuplehash[!dir].tuple, !manip)) |
489 | &ct->tuplehash[!dir].tuple, | ||
490 | !manip)) | ||
491 | return 0; | 482 | return 0; |
492 | 483 | ||
493 | if (skb->ip_summed != CHECKSUM_PARTIAL) { | 484 | if (skb->ip_summed != CHECKSUM_PARTIAL) { |
494 | /* Reloading "inside" here since manip_pkt inner. */ | 485 | /* Reloading "inside" here since manip_pkt inner. */ |
495 | inside = (void *)skb->data + ip_hdrlen(skb); | 486 | inside = (void *)skb->data + hdrlen; |
496 | inside->icmp.checksum = 0; | 487 | inside->icmp.checksum = 0; |
497 | inside->icmp.checksum = | 488 | inside->icmp.checksum = |
498 | csum_fold(skb_checksum(skb, hdrlen, | 489 | csum_fold(skb_checksum(skb, hdrlen, |
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c index 6c4f11f51446..3e61faf23a9a 100644 --- a/net/ipv4/netfilter/nf_nat_proto_common.c +++ b/net/ipv4/netfilter/nf_nat_proto_common.c | |||
@@ -34,7 +34,7 @@ bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, | |||
34 | } | 34 | } |
35 | EXPORT_SYMBOL_GPL(nf_nat_proto_in_range); | 35 | EXPORT_SYMBOL_GPL(nf_nat_proto_in_range); |
36 | 36 | ||
37 | bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, | 37 | void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, |
38 | const struct nf_nat_range *range, | 38 | const struct nf_nat_range *range, |
39 | enum nf_nat_manip_type maniptype, | 39 | enum nf_nat_manip_type maniptype, |
40 | const struct nf_conn *ct, | 40 | const struct nf_conn *ct, |
@@ -53,7 +53,7 @@ bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
53 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | 53 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { |
54 | /* If it's dst rewrite, can't change port */ | 54 | /* If it's dst rewrite, can't change port */ |
55 | if (maniptype == IP_NAT_MANIP_DST) | 55 | if (maniptype == IP_NAT_MANIP_DST) |
56 | return false; | 56 | return; |
57 | 57 | ||
58 | if (ntohs(*portptr) < 1024) { | 58 | if (ntohs(*portptr) < 1024) { |
59 | /* Loose convention: >> 512 is credential passing */ | 59 | /* Loose convention: >> 512 is credential passing */ |
@@ -81,15 +81,15 @@ bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
81 | else | 81 | else |
82 | off = *rover; | 82 | off = *rover; |
83 | 83 | ||
84 | for (i = 0; i < range_size; i++, off++) { | 84 | for (i = 0; ; ++off) { |
85 | *portptr = htons(min + off % range_size); | 85 | *portptr = htons(min + off % range_size); |
86 | if (nf_nat_used_tuple(tuple, ct)) | 86 | if (++i != range_size && nf_nat_used_tuple(tuple, ct)) |
87 | continue; | 87 | continue; |
88 | if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) | 88 | if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) |
89 | *rover = off; | 89 | *rover = off; |
90 | return true; | 90 | return; |
91 | } | 91 | } |
92 | return false; | 92 | return; |
93 | } | 93 | } |
94 | EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); | 94 | EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); |
95 | 95 | ||
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c index 22485ce306d4..570faf2667b2 100644 --- a/net/ipv4/netfilter/nf_nat_proto_dccp.c +++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c | |||
@@ -22,14 +22,14 @@ | |||
22 | 22 | ||
23 | static u_int16_t dccp_port_rover; | 23 | static u_int16_t dccp_port_rover; |
24 | 24 | ||
25 | static bool | 25 | static void |
26 | dccp_unique_tuple(struct nf_conntrack_tuple *tuple, | 26 | dccp_unique_tuple(struct nf_conntrack_tuple *tuple, |
27 | const struct nf_nat_range *range, | 27 | const struct nf_nat_range *range, |
28 | enum nf_nat_manip_type maniptype, | 28 | enum nf_nat_manip_type maniptype, |
29 | const struct nf_conn *ct) | 29 | const struct nf_conn *ct) |
30 | { | 30 | { |
31 | return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, | 31 | nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, |
32 | &dccp_port_rover); | 32 | &dccp_port_rover); |
33 | } | 33 | } |
34 | 34 | ||
35 | static bool | 35 | static bool |
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index d7e89201351e..bc8d83a31c73 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c | |||
@@ -37,7 +37,7 @@ MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | |||
37 | MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); | 37 | MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); |
38 | 38 | ||
39 | /* generate unique tuple ... */ | 39 | /* generate unique tuple ... */ |
40 | static bool | 40 | static void |
41 | gre_unique_tuple(struct nf_conntrack_tuple *tuple, | 41 | gre_unique_tuple(struct nf_conntrack_tuple *tuple, |
42 | const struct nf_nat_range *range, | 42 | const struct nf_nat_range *range, |
43 | enum nf_nat_manip_type maniptype, | 43 | enum nf_nat_manip_type maniptype, |
@@ -50,7 +50,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
50 | /* If there is no master conntrack we are not PPTP, | 50 | /* If there is no master conntrack we are not PPTP, |
51 | do not change tuples */ | 51 | do not change tuples */ |
52 | if (!ct->master) | 52 | if (!ct->master) |
53 | return false; | 53 | return; |
54 | 54 | ||
55 | if (maniptype == IP_NAT_MANIP_SRC) | 55 | if (maniptype == IP_NAT_MANIP_SRC) |
56 | keyptr = &tuple->src.u.gre.key; | 56 | keyptr = &tuple->src.u.gre.key; |
@@ -68,14 +68,14 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
68 | 68 | ||
69 | pr_debug("min = %u, range_size = %u\n", min, range_size); | 69 | pr_debug("min = %u, range_size = %u\n", min, range_size); |
70 | 70 | ||
71 | for (i = 0; i < range_size; i++, key++) { | 71 | for (i = 0; ; ++key) { |
72 | *keyptr = htons(min + key % range_size); | 72 | *keyptr = htons(min + key % range_size); |
73 | if (!nf_nat_used_tuple(tuple, ct)) | 73 | if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) |
74 | return true; | 74 | return; |
75 | } | 75 | } |
76 | 76 | ||
77 | pr_debug("%p: no NAT mapping\n", ct); | 77 | pr_debug("%p: no NAT mapping\n", ct); |
78 | return false; | 78 | return; |
79 | } | 79 | } |
80 | 80 | ||
81 | /* manipulate a GRE packet according to maniptype */ | 81 | /* manipulate a GRE packet according to maniptype */ |
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index 19a8b0b07d8e..5744c3ec847c 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c | |||
@@ -27,7 +27,7 @@ icmp_in_range(const struct nf_conntrack_tuple *tuple, | |||
27 | ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); | 27 | ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); |
28 | } | 28 | } |
29 | 29 | ||
30 | static bool | 30 | static void |
31 | icmp_unique_tuple(struct nf_conntrack_tuple *tuple, | 31 | icmp_unique_tuple(struct nf_conntrack_tuple *tuple, |
32 | const struct nf_nat_range *range, | 32 | const struct nf_nat_range *range, |
33 | enum nf_nat_manip_type maniptype, | 33 | enum nf_nat_manip_type maniptype, |
@@ -42,13 +42,13 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple, | |||
42 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) | 42 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) |
43 | range_size = 0xFFFF; | 43 | range_size = 0xFFFF; |
44 | 44 | ||
45 | for (i = 0; i < range_size; i++, id++) { | 45 | for (i = 0; ; ++id) { |
46 | tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + | 46 | tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + |
47 | (id % range_size)); | 47 | (id % range_size)); |
48 | if (!nf_nat_used_tuple(tuple, ct)) | 48 | if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) |
49 | return true; | 49 | return; |
50 | } | 50 | } |
51 | return false; | 51 | return; |
52 | } | 52 | } |
53 | 53 | ||
54 | static bool | 54 | static bool |
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c index 3fc598eeeb1a..756331d42661 100644 --- a/net/ipv4/netfilter/nf_nat_proto_sctp.c +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c | |||
@@ -16,14 +16,14 @@ | |||
16 | 16 | ||
17 | static u_int16_t nf_sctp_port_rover; | 17 | static u_int16_t nf_sctp_port_rover; |
18 | 18 | ||
19 | static bool | 19 | static void |
20 | sctp_unique_tuple(struct nf_conntrack_tuple *tuple, | 20 | sctp_unique_tuple(struct nf_conntrack_tuple *tuple, |
21 | const struct nf_nat_range *range, | 21 | const struct nf_nat_range *range, |
22 | enum nf_nat_manip_type maniptype, | 22 | enum nf_nat_manip_type maniptype, |
23 | const struct nf_conn *ct) | 23 | const struct nf_conn *ct) |
24 | { | 24 | { |
25 | return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, | 25 | nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, |
26 | &nf_sctp_port_rover); | 26 | &nf_sctp_port_rover); |
27 | } | 27 | } |
28 | 28 | ||
29 | static bool | 29 | static bool |
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index 399e2cfa263b..aa460a595d5d 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c | |||
@@ -20,14 +20,13 @@ | |||
20 | 20 | ||
21 | static u_int16_t tcp_port_rover; | 21 | static u_int16_t tcp_port_rover; |
22 | 22 | ||
23 | static bool | 23 | static void |
24 | tcp_unique_tuple(struct nf_conntrack_tuple *tuple, | 24 | tcp_unique_tuple(struct nf_conntrack_tuple *tuple, |
25 | const struct nf_nat_range *range, | 25 | const struct nf_nat_range *range, |
26 | enum nf_nat_manip_type maniptype, | 26 | enum nf_nat_manip_type maniptype, |
27 | const struct nf_conn *ct) | 27 | const struct nf_conn *ct) |
28 | { | 28 | { |
29 | return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, | 29 | nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover); |
30 | &tcp_port_rover); | ||
31 | } | 30 | } |
32 | 31 | ||
33 | static bool | 32 | static bool |
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index 9e61c79492e4..dfe65c7e2925 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c | |||
@@ -19,14 +19,13 @@ | |||
19 | 19 | ||
20 | static u_int16_t udp_port_rover; | 20 | static u_int16_t udp_port_rover; |
21 | 21 | ||
22 | static bool | 22 | static void |
23 | udp_unique_tuple(struct nf_conntrack_tuple *tuple, | 23 | udp_unique_tuple(struct nf_conntrack_tuple *tuple, |
24 | const struct nf_nat_range *range, | 24 | const struct nf_nat_range *range, |
25 | enum nf_nat_manip_type maniptype, | 25 | enum nf_nat_manip_type maniptype, |
26 | const struct nf_conn *ct) | 26 | const struct nf_conn *ct) |
27 | { | 27 | { |
28 | return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, | 28 | nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &udp_port_rover); |
29 | &udp_port_rover); | ||
30 | } | 29 | } |
31 | 30 | ||
32 | static bool | 31 | static bool |
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c index 440a229bbd87..3cc8c8af39ef 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udplite.c +++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c | |||
@@ -18,14 +18,14 @@ | |||
18 | 18 | ||
19 | static u_int16_t udplite_port_rover; | 19 | static u_int16_t udplite_port_rover; |
20 | 20 | ||
21 | static bool | 21 | static void |
22 | udplite_unique_tuple(struct nf_conntrack_tuple *tuple, | 22 | udplite_unique_tuple(struct nf_conntrack_tuple *tuple, |
23 | const struct nf_nat_range *range, | 23 | const struct nf_nat_range *range, |
24 | enum nf_nat_manip_type maniptype, | 24 | enum nf_nat_manip_type maniptype, |
25 | const struct nf_conn *ct) | 25 | const struct nf_conn *ct) |
26 | { | 26 | { |
27 | return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, | 27 | nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, |
28 | &udplite_port_rover); | 28 | &udplite_port_rover); |
29 | } | 29 | } |
30 | 30 | ||
31 | static bool | 31 | static bool |
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c index 14381c62acea..a50f2bc1c732 100644 --- a/net/ipv4/netfilter/nf_nat_proto_unknown.c +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c | |||
@@ -26,14 +26,14 @@ static bool unknown_in_range(const struct nf_conntrack_tuple *tuple, | |||
26 | return true; | 26 | return true; |
27 | } | 27 | } |
28 | 28 | ||
29 | static bool unknown_unique_tuple(struct nf_conntrack_tuple *tuple, | 29 | static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple, |
30 | const struct nf_nat_range *range, | 30 | const struct nf_nat_range *range, |
31 | enum nf_nat_manip_type maniptype, | 31 | enum nf_nat_manip_type maniptype, |
32 | const struct nf_conn *ct) | 32 | const struct nf_conn *ct) |
33 | { | 33 | { |
34 | /* Sorry: we can't help you; if it's not unique, we can't frob | 34 | /* Sorry: we can't help you; if it's not unique, we can't frob |
35 | anything. */ | 35 | anything. */ |
36 | return false; | 36 | return; |
37 | } | 37 | } |
38 | 38 | ||
39 | static bool | 39 | static bool |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 562ce92de2a6..3f56b6e6c6aa 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2878,6 +2878,9 @@ static int rt_fill_info(struct net *net, | |||
2878 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) | 2878 | if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0) |
2879 | goto nla_put_failure; | 2879 | goto nla_put_failure; |
2880 | 2880 | ||
2881 | if (rt->fl.mark) | ||
2882 | NLA_PUT_BE32(skb, RTA_MARK, rt->fl.mark); | ||
2883 | |||
2881 | error = rt->dst.error; | 2884 | error = rt->dst.error; |
2882 | expires = rt->dst.expires ? rt->dst.expires - jiffies : 0; | 2885 | expires = rt->dst.expires ? rt->dst.expires - jiffies : 0; |
2883 | if (rt->peer) { | 2886 | if (rt->peer) { |
@@ -2933,6 +2936,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2933 | __be32 src = 0; | 2936 | __be32 src = 0; |
2934 | u32 iif; | 2937 | u32 iif; |
2935 | int err; | 2938 | int err; |
2939 | int mark; | ||
2936 | struct sk_buff *skb; | 2940 | struct sk_buff *skb; |
2937 | 2941 | ||
2938 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); | 2942 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); |
@@ -2960,6 +2964,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2960 | src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0; | 2964 | src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0; |
2961 | dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0; | 2965 | dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0; |
2962 | iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; | 2966 | iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; |
2967 | mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0; | ||
2963 | 2968 | ||
2964 | if (iif) { | 2969 | if (iif) { |
2965 | struct net_device *dev; | 2970 | struct net_device *dev; |
@@ -2972,6 +2977,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2972 | 2977 | ||
2973 | skb->protocol = htons(ETH_P_IP); | 2978 | skb->protocol = htons(ETH_P_IP); |
2974 | skb->dev = dev; | 2979 | skb->dev = dev; |
2980 | skb->mark = mark; | ||
2975 | local_bh_disable(); | 2981 | local_bh_disable(); |
2976 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); | 2982 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); |
2977 | local_bh_enable(); | 2983 | local_bh_enable(); |
@@ -2989,6 +2995,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2989 | }, | 2995 | }, |
2990 | }, | 2996 | }, |
2991 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | 2997 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, |
2998 | .mark = mark, | ||
2992 | }; | 2999 | }; |
2993 | err = ip_route_output_key(net, &rt, &fl); | 3000 | err = ip_route_output_key(net, &rt, &fl); |
2994 | } | 3001 | } |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 86b9f67abede..176e11aaea77 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -2187,6 +2187,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
2187 | GFP_KERNEL); | 2187 | GFP_KERNEL); |
2188 | if (cvp == NULL) | 2188 | if (cvp == NULL) |
2189 | return -ENOMEM; | 2189 | return -ENOMEM; |
2190 | |||
2191 | kref_init(&cvp->kref); | ||
2190 | } | 2192 | } |
2191 | lock_sock(sk); | 2193 | lock_sock(sk); |
2192 | tp->rx_opt.cookie_in_always = | 2194 | tp->rx_opt.cookie_in_always = |
@@ -2201,12 +2203,11 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
2201 | */ | 2203 | */ |
2202 | kref_put(&tp->cookie_values->kref, | 2204 | kref_put(&tp->cookie_values->kref, |
2203 | tcp_cookie_values_release); | 2205 | tcp_cookie_values_release); |
2204 | kref_init(&cvp->kref); | ||
2205 | tp->cookie_values = cvp; | ||
2206 | } else { | 2206 | } else { |
2207 | cvp = tp->cookie_values; | 2207 | cvp = tp->cookie_values; |
2208 | } | 2208 | } |
2209 | } | 2209 | } |
2210 | |||
2210 | if (cvp != NULL) { | 2211 | if (cvp != NULL) { |
2211 | cvp->cookie_desired = ctd.tcpct_cookie_desired; | 2212 | cvp->cookie_desired = ctd.tcpct_cookie_desired; |
2212 | 2213 | ||
@@ -2220,6 +2221,8 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
2220 | cvp->s_data_desired = ctd.tcpct_s_data_desired; | 2221 | cvp->s_data_desired = ctd.tcpct_s_data_desired; |
2221 | cvp->s_data_constant = 0; /* false */ | 2222 | cvp->s_data_constant = 0; /* false */ |
2222 | } | 2223 | } |
2224 | |||
2225 | tp->cookie_values = cvp; | ||
2223 | } | 2226 | } |
2224 | release_sock(sk); | 2227 | release_sock(sk); |
2225 | return err; | 2228 | return err; |
@@ -2601,6 +2604,12 @@ static int do_tcp_getsockopt(struct sock *sk, int level, | |||
2601 | return -EFAULT; | 2604 | return -EFAULT; |
2602 | return 0; | 2605 | return 0; |
2603 | } | 2606 | } |
2607 | case TCP_THIN_LINEAR_TIMEOUTS: | ||
2608 | val = tp->thin_lto; | ||
2609 | break; | ||
2610 | case TCP_THIN_DUPACK: | ||
2611 | val = tp->thin_dupack; | ||
2612 | break; | ||
2604 | default: | 2613 | default: |
2605 | return -ENOPROTOOPT; | 2614 | return -ENOPROTOOPT; |
2606 | } | 2615 | } |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e81155d2f251..ab70a3fbcafa 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -1763,7 +1763,10 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev) | |||
1763 | 1763 | ||
1764 | idev = ipv6_find_idev(dev); | 1764 | idev = ipv6_find_idev(dev); |
1765 | if (!idev) | 1765 | if (!idev) |
1766 | return NULL; | 1766 | return ERR_PTR(-ENOBUFS); |
1767 | |||
1768 | if (idev->cnf.disable_ipv6) | ||
1769 | return ERR_PTR(-EACCES); | ||
1767 | 1770 | ||
1768 | /* Add default multicast route */ | 1771 | /* Add default multicast route */ |
1769 | addrconf_add_mroute(dev); | 1772 | addrconf_add_mroute(dev); |
@@ -2132,8 +2135,9 @@ static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, | |||
2132 | if (!dev) | 2135 | if (!dev) |
2133 | return -ENODEV; | 2136 | return -ENODEV; |
2134 | 2137 | ||
2135 | if ((idev = addrconf_add_dev(dev)) == NULL) | 2138 | idev = addrconf_add_dev(dev); |
2136 | return -ENOBUFS; | 2139 | if (IS_ERR(idev)) |
2140 | return PTR_ERR(idev); | ||
2137 | 2141 | ||
2138 | scope = ipv6_addr_scope(pfx); | 2142 | scope = ipv6_addr_scope(pfx); |
2139 | 2143 | ||
@@ -2380,7 +2384,7 @@ static void addrconf_dev_config(struct net_device *dev) | |||
2380 | } | 2384 | } |
2381 | 2385 | ||
2382 | idev = addrconf_add_dev(dev); | 2386 | idev = addrconf_add_dev(dev); |
2383 | if (idev == NULL) | 2387 | if (IS_ERR(idev)) |
2384 | return; | 2388 | return; |
2385 | 2389 | ||
2386 | memset(&addr, 0, sizeof(struct in6_addr)); | 2390 | memset(&addr, 0, sizeof(struct in6_addr)); |
@@ -2471,7 +2475,7 @@ static void addrconf_ip6_tnl_config(struct net_device *dev) | |||
2471 | ASSERT_RTNL(); | 2475 | ASSERT_RTNL(); |
2472 | 2476 | ||
2473 | idev = addrconf_add_dev(dev); | 2477 | idev = addrconf_add_dev(dev); |
2474 | if (!idev) { | 2478 | if (IS_ERR(idev)) { |
2475 | printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n"); | 2479 | printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n"); |
2476 | return; | 2480 | return; |
2477 | } | 2481 | } |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index dc41d6d3c6c6..5359ef4daac5 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -387,9 +387,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
387 | goto no_match; | 387 | goto no_match; |
388 | } | 388 | } |
389 | 389 | ||
390 | ADD_COUNTER(e->counters, | 390 | ADD_COUNTER(e->counters, skb->len, 1); |
391 | ntohs(ipv6_hdr(skb)->payload_len) + | ||
392 | sizeof(struct ipv6hdr), 1); | ||
393 | 391 | ||
394 | t = ip6t_get_target_c(e); | 392 | t = ip6t_get_target_c(e); |
395 | IP_NF_ASSERT(t->u.kernel.target); | 393 | IP_NF_ASSERT(t->u.kernel.target); |
@@ -899,7 +897,7 @@ get_counters(const struct xt_table_info *t, | |||
899 | struct ip6t_entry *iter; | 897 | struct ip6t_entry *iter; |
900 | unsigned int cpu; | 898 | unsigned int cpu; |
901 | unsigned int i; | 899 | unsigned int i; |
902 | unsigned int curcpu; | 900 | unsigned int curcpu = get_cpu(); |
903 | 901 | ||
904 | /* Instead of clearing (by a previous call to memset()) | 902 | /* Instead of clearing (by a previous call to memset()) |
905 | * the counters and using adds, we set the counters | 903 | * the counters and using adds, we set the counters |
@@ -909,14 +907,16 @@ get_counters(const struct xt_table_info *t, | |||
909 | * if new softirq were to run and call ipt_do_table | 907 | * if new softirq were to run and call ipt_do_table |
910 | */ | 908 | */ |
911 | local_bh_disable(); | 909 | local_bh_disable(); |
912 | curcpu = smp_processor_id(); | ||
913 | |||
914 | i = 0; | 910 | i = 0; |
915 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { | 911 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
916 | SET_COUNTER(counters[i], iter->counters.bcnt, | 912 | SET_COUNTER(counters[i], iter->counters.bcnt, |
917 | iter->counters.pcnt); | 913 | iter->counters.pcnt); |
918 | ++i; | 914 | ++i; |
919 | } | 915 | } |
916 | local_bh_enable(); | ||
917 | /* Processing counters from other cpus, we can let bottom half enabled, | ||
918 | * (preemption is disabled) | ||
919 | */ | ||
920 | 920 | ||
921 | for_each_possible_cpu(cpu) { | 921 | for_each_possible_cpu(cpu) { |
922 | if (cpu == curcpu) | 922 | if (cpu == curcpu) |
@@ -930,7 +930,7 @@ get_counters(const struct xt_table_info *t, | |||
930 | } | 930 | } |
931 | xt_info_wrunlock(cpu); | 931 | xt_info_wrunlock(cpu); |
932 | } | 932 | } |
933 | local_bh_enable(); | 933 | put_cpu(); |
934 | } | 934 | } |
935 | 935 | ||
936 | static struct xt_counters *alloc_counters(const struct xt_table *table) | 936 | static struct xt_counters *alloc_counters(const struct xt_table *table) |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 9254008602d4..098a050a20b0 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -269,6 +269,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
269 | * in the chain of fragments so far. We must know where to put | 269 | * in the chain of fragments so far. We must know where to put |
270 | * this fragment, right? | 270 | * this fragment, right? |
271 | */ | 271 | */ |
272 | prev = fq->q.fragments_tail; | ||
273 | if (!prev || NFCT_FRAG6_CB(prev)->offset < offset) { | ||
274 | next = NULL; | ||
275 | goto found; | ||
276 | } | ||
272 | prev = NULL; | 277 | prev = NULL; |
273 | for (next = fq->q.fragments; next != NULL; next = next->next) { | 278 | for (next = fq->q.fragments; next != NULL; next = next->next) { |
274 | if (NFCT_FRAG6_CB(next)->offset >= offset) | 279 | if (NFCT_FRAG6_CB(next)->offset >= offset) |
@@ -276,6 +281,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
276 | prev = next; | 281 | prev = next; |
277 | } | 282 | } |
278 | 283 | ||
284 | found: | ||
279 | /* We found where to put this one. Check for overlap with | 285 | /* We found where to put this one. Check for overlap with |
280 | * preceding fragment, and, if needed, align things so that | 286 | * preceding fragment, and, if needed, align things so that |
281 | * any overlaps are eliminated. | 287 | * any overlaps are eliminated. |
@@ -341,6 +347,8 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, | |||
341 | 347 | ||
342 | /* Insert this fragment in the chain of fragments. */ | 348 | /* Insert this fragment in the chain of fragments. */ |
343 | skb->next = next; | 349 | skb->next = next; |
350 | if (!next) | ||
351 | fq->q.fragments_tail = skb; | ||
344 | if (prev) | 352 | if (prev) |
345 | prev->next = skb; | 353 | prev->next = skb; |
346 | else | 354 | else |
@@ -464,6 +472,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
464 | head->csum); | 472 | head->csum); |
465 | 473 | ||
466 | fq->q.fragments = NULL; | 474 | fq->q.fragments = NULL; |
475 | fq->q.fragments_tail = NULL; | ||
467 | 476 | ||
468 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | 477 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ |
469 | fp = skb_shinfo(head)->frag_list; | 478 | fp = skb_shinfo(head)->frag_list; |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index dab6b8efe5fa..29ac8e1a509e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -627,7 +627,7 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) | |||
627 | skb->dev = sta->sdata->dev; | 627 | skb->dev = sta->sdata->dev; |
628 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); | 628 | skb->protocol = eth_type_trans(skb, sta->sdata->dev); |
629 | memset(skb->cb, 0, sizeof(skb->cb)); | 629 | memset(skb->cb, 0, sizeof(skb->cb)); |
630 | netif_rx(skb); | 630 | netif_rx_ni(skb); |
631 | } | 631 | } |
632 | 632 | ||
633 | static void sta_apply_parameters(struct ieee80211_local *local, | 633 | static void sta_apply_parameters(struct ieee80211_local *local, |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 7cc4f913a431..798a91b100cc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -685,10 +685,12 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
685 | 685 | ||
686 | return 0; | 686 | return 0; |
687 | 687 | ||
688 | #ifdef CONFIG_INET | ||
688 | fail_ifa: | 689 | fail_ifa: |
689 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, | 690 | pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY, |
690 | &local->network_latency_notifier); | 691 | &local->network_latency_notifier); |
691 | rtnl_lock(); | 692 | rtnl_lock(); |
693 | #endif | ||
692 | fail_pm_qos: | 694 | fail_pm_qos: |
693 | ieee80211_led_exit(local); | 695 | ieee80211_led_exit(local); |
694 | ieee80211_remove_interfaces(local); | 696 | ieee80211_remove_interfaces(local); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 41f20fb7e670..872d7b6ef6b3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -400,19 +400,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
400 | else | 400 | else |
401 | __set_bit(SCAN_SW_SCANNING, &local->scanning); | 401 | __set_bit(SCAN_SW_SCANNING, &local->scanning); |
402 | 402 | ||
403 | /* | ||
404 | * Kicking off the scan need not be protected, | ||
405 | * only the scan variable stuff, since now | ||
406 | * local->scan_req is assigned and other callers | ||
407 | * will abort their scan attempts. | ||
408 | * | ||
409 | * This avoids too many locking dependencies | ||
410 | * so that the scan completed calls have more | ||
411 | * locking freedom. | ||
412 | */ | ||
413 | |||
414 | ieee80211_recalc_idle(local); | 403 | ieee80211_recalc_idle(local); |
415 | mutex_unlock(&local->scan_mtx); | ||
416 | 404 | ||
417 | if (local->ops->hw_scan) { | 405 | if (local->ops->hw_scan) { |
418 | WARN_ON(!ieee80211_prep_hw_scan(local)); | 406 | WARN_ON(!ieee80211_prep_hw_scan(local)); |
@@ -420,8 +408,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
420 | } else | 408 | } else |
421 | rc = ieee80211_start_sw_scan(local); | 409 | rc = ieee80211_start_sw_scan(local); |
422 | 410 | ||
423 | mutex_lock(&local->scan_mtx); | ||
424 | |||
425 | if (rc) { | 411 | if (rc) { |
426 | kfree(local->hw_scan_req); | 412 | kfree(local->hw_scan_req); |
427 | local->hw_scan_req = NULL; | 413 | local->hw_scan_req = NULL; |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index aa2f106347e4..43288259f4a1 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -326,6 +326,22 @@ config NETFILTER_XT_CONNMARK | |||
326 | 326 | ||
327 | comment "Xtables targets" | 327 | comment "Xtables targets" |
328 | 328 | ||
329 | config NETFILTER_XT_TARGET_CHECKSUM | ||
330 | tristate "CHECKSUM target support" | ||
331 | depends on IP_NF_MANGLE || IP6_NF_MANGLE | ||
332 | depends on NETFILTER_ADVANCED | ||
333 | ---help--- | ||
334 | This option adds a `CHECKSUM' target, which can be used in the iptables mangle | ||
335 | table. | ||
336 | |||
337 | You can use this target to compute and fill in the checksum in | ||
338 | a packet that lacks a checksum. This is particularly useful, | ||
339 | if you need to work around old applications such as dhcp clients, | ||
340 | that do not work well with checksum offloads, but don't want to disable | ||
341 | checksum offload in your device. | ||
342 | |||
343 | To compile it as a module, choose M here. If unsure, say N. | ||
344 | |||
329 | config NETFILTER_XT_TARGET_CLASSIFY | 345 | config NETFILTER_XT_TARGET_CLASSIFY |
330 | tristate '"CLASSIFY" target support' | 346 | tristate '"CLASSIFY" target support' |
331 | depends on NETFILTER_ADVANCED | 347 | depends on NETFILTER_ADVANCED |
@@ -647,6 +663,15 @@ config NETFILTER_XT_MATCH_CONNTRACK | |||
647 | 663 | ||
648 | To compile it as a module, choose M here. If unsure, say N. | 664 | To compile it as a module, choose M here. If unsure, say N. |
649 | 665 | ||
666 | config NETFILTER_XT_MATCH_CPU | ||
667 | tristate '"cpu" match support' | ||
668 | depends on NETFILTER_ADVANCED | ||
669 | help | ||
670 | CPU matching allows you to match packets based on the CPU | ||
671 | currently handling the packet. | ||
672 | |||
673 | To compile it as a module, choose M here. If unsure, say N. | ||
674 | |||
650 | config NETFILTER_XT_MATCH_DCCP | 675 | config NETFILTER_XT_MATCH_DCCP |
651 | tristate '"dccp" protocol match support' | 676 | tristate '"dccp" protocol match support' |
652 | depends on NETFILTER_ADVANCED | 677 | depends on NETFILTER_ADVANCED |
@@ -726,6 +751,16 @@ config NETFILTER_XT_MATCH_IPRANGE | |||
726 | 751 | ||
727 | If unsure, say M. | 752 | If unsure, say M. |
728 | 753 | ||
754 | config NETFILTER_XT_MATCH_IPVS | ||
755 | tristate '"ipvs" match support' | ||
756 | depends on IP_VS | ||
757 | depends on NETFILTER_ADVANCED | ||
758 | depends on NF_CONNTRACK | ||
759 | help | ||
760 | This option allows you to match against IPVS properties of a packet. | ||
761 | |||
762 | If unsure, say N. | ||
763 | |||
729 | config NETFILTER_XT_MATCH_LENGTH | 764 | config NETFILTER_XT_MATCH_LENGTH |
730 | tristate '"length" match support' | 765 | tristate '"length" match support' |
731 | depends on NETFILTER_ADVANCED | 766 | depends on NETFILTER_ADVANCED |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index e28420aac5ef..441050f31111 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -45,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o | |||
45 | obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o | 45 | obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o |
46 | 46 | ||
47 | # targets | 47 | # targets |
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_CHECKSUM) += xt_CHECKSUM.o | ||
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o | 49 | obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o |
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o | 50 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o |
50 | obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o | 51 | obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o |
@@ -69,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o | |||
69 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o | 70 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o |
70 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o | 71 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o |
71 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o | 72 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o |
73 | obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o | ||
72 | obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o | 74 | obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o |
73 | obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o | 75 | obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o |
74 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o | 76 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o |
@@ -76,6 +78,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o | |||
76 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o | 78 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o |
77 | obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o | 79 | obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o |
78 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o | 80 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o |
81 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPVS) += xt_ipvs.o | ||
79 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | 82 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o |
80 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o | 83 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o |
81 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o | 84 | obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o |
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index 712ccad13344..46a77d5c3887 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | menuconfig IP_VS | 4 | menuconfig IP_VS |
5 | tristate "IP virtual server support" | 5 | tristate "IP virtual server support" |
6 | depends on NET && INET && NETFILTER | 6 | depends on NET && INET && NETFILTER && NF_CONNTRACK |
7 | ---help--- | 7 | ---help--- |
8 | IP Virtual Server support will let you build a high-performance | 8 | IP Virtual Server support will let you build a high-performance |
9 | virtual server based on cluster of two or more real servers. This | 9 | virtual server based on cluster of two or more real servers. This |
@@ -26,7 +26,7 @@ if IP_VS | |||
26 | 26 | ||
27 | config IP_VS_IPV6 | 27 | config IP_VS_IPV6 |
28 | bool "IPv6 support for IPVS" | 28 | bool "IPv6 support for IPVS" |
29 | depends on EXPERIMENTAL && (IPV6 = y || IP_VS = IPV6) | 29 | depends on IPV6 = y || IP_VS = IPV6 |
30 | ---help--- | 30 | ---help--- |
31 | Add IPv6 support to IPVS. This is incomplete and might be dangerous. | 31 | Add IPv6 support to IPVS. This is incomplete and might be dangerous. |
32 | 32 | ||
@@ -87,19 +87,16 @@ config IP_VS_PROTO_UDP | |||
87 | protocol. Say Y if unsure. | 87 | protocol. Say Y if unsure. |
88 | 88 | ||
89 | config IP_VS_PROTO_AH_ESP | 89 | config IP_VS_PROTO_AH_ESP |
90 | bool | 90 | def_bool IP_VS_PROTO_ESP || IP_VS_PROTO_AH |
91 | depends on UNDEFINED | ||
92 | 91 | ||
93 | config IP_VS_PROTO_ESP | 92 | config IP_VS_PROTO_ESP |
94 | bool "ESP load balancing support" | 93 | bool "ESP load balancing support" |
95 | select IP_VS_PROTO_AH_ESP | ||
96 | ---help--- | 94 | ---help--- |
97 | This option enables support for load balancing ESP (Encapsulation | 95 | This option enables support for load balancing ESP (Encapsulation |
98 | Security Payload) transport protocol. Say Y if unsure. | 96 | Security Payload) transport protocol. Say Y if unsure. |
99 | 97 | ||
100 | config IP_VS_PROTO_AH | 98 | config IP_VS_PROTO_AH |
101 | bool "AH load balancing support" | 99 | bool "AH load balancing support" |
102 | select IP_VS_PROTO_AH_ESP | ||
103 | ---help--- | 100 | ---help--- |
104 | This option enables support for load balancing AH (Authentication | 101 | This option enables support for load balancing AH (Authentication |
105 | Header) transport protocol. Say Y if unsure. | 102 | Header) transport protocol. Say Y if unsure. |
@@ -238,7 +235,7 @@ comment 'IPVS application helper' | |||
238 | 235 | ||
239 | config IP_VS_FTP | 236 | config IP_VS_FTP |
240 | tristate "FTP protocol helper" | 237 | tristate "FTP protocol helper" |
241 | depends on IP_VS_PROTO_TCP | 238 | depends on IP_VS_PROTO_TCP && NF_NAT |
242 | ---help--- | 239 | ---help--- |
243 | FTP is a protocol that transfers IP address and/or port number in | 240 | FTP is a protocol that transfers IP address and/or port number in |
244 | the payload. In the virtual server via Network Address Translation, | 241 | the payload. In the virtual server via Network Address Translation, |
diff --git a/net/netfilter/ipvs/ip_vs_app.c b/net/netfilter/ipvs/ip_vs_app.c index 1cb0e834f8ff..e76f87f4aca8 100644 --- a/net/netfilter/ipvs/ip_vs_app.c +++ b/net/netfilter/ipvs/ip_vs_app.c | |||
@@ -569,49 +569,6 @@ static const struct file_operations ip_vs_app_fops = { | |||
569 | }; | 569 | }; |
570 | #endif | 570 | #endif |
571 | 571 | ||
572 | |||
573 | /* | ||
574 | * Replace a segment of data with a new segment | ||
575 | */ | ||
576 | int ip_vs_skb_replace(struct sk_buff *skb, gfp_t pri, | ||
577 | char *o_buf, int o_len, char *n_buf, int n_len) | ||
578 | { | ||
579 | int diff; | ||
580 | int o_offset; | ||
581 | int o_left; | ||
582 | |||
583 | EnterFunction(9); | ||
584 | |||
585 | diff = n_len - o_len; | ||
586 | o_offset = o_buf - (char *)skb->data; | ||
587 | /* The length of left data after o_buf+o_len in the skb data */ | ||
588 | o_left = skb->len - (o_offset + o_len); | ||
589 | |||
590 | if (diff <= 0) { | ||
591 | memmove(o_buf + n_len, o_buf + o_len, o_left); | ||
592 | memcpy(o_buf, n_buf, n_len); | ||
593 | skb_trim(skb, skb->len + diff); | ||
594 | } else if (diff <= skb_tailroom(skb)) { | ||
595 | skb_put(skb, diff); | ||
596 | memmove(o_buf + n_len, o_buf + o_len, o_left); | ||
597 | memcpy(o_buf, n_buf, n_len); | ||
598 | } else { | ||
599 | if (pskb_expand_head(skb, skb_headroom(skb), diff, pri)) | ||
600 | return -ENOMEM; | ||
601 | skb_put(skb, diff); | ||
602 | memmove(skb->data + o_offset + n_len, | ||
603 | skb->data + o_offset + o_len, o_left); | ||
604 | skb_copy_to_linear_data_offset(skb, o_offset, n_buf, n_len); | ||
605 | } | ||
606 | |||
607 | /* must update the iph total length here */ | ||
608 | ip_hdr(skb)->tot_len = htons(skb->len); | ||
609 | |||
610 | LeaveFunction(9); | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | |||
615 | int __init ip_vs_app_init(void) | 572 | int __init ip_vs_app_init(void) |
616 | { | 573 | { |
617 | /* we will replace it with proc_net_ipvs_create() soon */ | 574 | /* we will replace it with proc_net_ipvs_create() soon */ |
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 654544e72264..b71c69a2db13 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c | |||
@@ -271,6 +271,29 @@ struct ip_vs_conn *ip_vs_conn_in_get | |||
271 | return cp; | 271 | return cp; |
272 | } | 272 | } |
273 | 273 | ||
274 | struct ip_vs_conn * | ||
275 | ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb, | ||
276 | struct ip_vs_protocol *pp, | ||
277 | const struct ip_vs_iphdr *iph, | ||
278 | unsigned int proto_off, int inverse) | ||
279 | { | ||
280 | __be16 _ports[2], *pptr; | ||
281 | |||
282 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
283 | if (pptr == NULL) | ||
284 | return NULL; | ||
285 | |||
286 | if (likely(!inverse)) | ||
287 | return ip_vs_conn_in_get(af, iph->protocol, | ||
288 | &iph->saddr, pptr[0], | ||
289 | &iph->daddr, pptr[1]); | ||
290 | else | ||
291 | return ip_vs_conn_in_get(af, iph->protocol, | ||
292 | &iph->daddr, pptr[1], | ||
293 | &iph->saddr, pptr[0]); | ||
294 | } | ||
295 | EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto); | ||
296 | |||
274 | /* Get reference to connection template */ | 297 | /* Get reference to connection template */ |
275 | struct ip_vs_conn *ip_vs_ct_in_get | 298 | struct ip_vs_conn *ip_vs_ct_in_get |
276 | (int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port, | 299 | (int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port, |
@@ -356,6 +379,28 @@ struct ip_vs_conn *ip_vs_conn_out_get | |||
356 | return ret; | 379 | return ret; |
357 | } | 380 | } |
358 | 381 | ||
382 | struct ip_vs_conn * | ||
383 | ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb, | ||
384 | struct ip_vs_protocol *pp, | ||
385 | const struct ip_vs_iphdr *iph, | ||
386 | unsigned int proto_off, int inverse) | ||
387 | { | ||
388 | __be16 _ports[2], *pptr; | ||
389 | |||
390 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
391 | if (pptr == NULL) | ||
392 | return NULL; | ||
393 | |||
394 | if (likely(!inverse)) | ||
395 | return ip_vs_conn_out_get(af, iph->protocol, | ||
396 | &iph->saddr, pptr[0], | ||
397 | &iph->daddr, pptr[1]); | ||
398 | else | ||
399 | return ip_vs_conn_out_get(af, iph->protocol, | ||
400 | &iph->daddr, pptr[1], | ||
401 | &iph->saddr, pptr[0]); | ||
402 | } | ||
403 | EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto); | ||
359 | 404 | ||
360 | /* | 405 | /* |
361 | * Put back the conn and restart its timer with its timeout | 406 | * Put back the conn and restart its timer with its timeout |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 50907d8472a3..4f8ddba48011 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -54,7 +54,6 @@ | |||
54 | 54 | ||
55 | EXPORT_SYMBOL(register_ip_vs_scheduler); | 55 | EXPORT_SYMBOL(register_ip_vs_scheduler); |
56 | EXPORT_SYMBOL(unregister_ip_vs_scheduler); | 56 | EXPORT_SYMBOL(unregister_ip_vs_scheduler); |
57 | EXPORT_SYMBOL(ip_vs_skb_replace); | ||
58 | EXPORT_SYMBOL(ip_vs_proto_name); | 57 | EXPORT_SYMBOL(ip_vs_proto_name); |
59 | EXPORT_SYMBOL(ip_vs_conn_new); | 58 | EXPORT_SYMBOL(ip_vs_conn_new); |
60 | EXPORT_SYMBOL(ip_vs_conn_in_get); | 59 | EXPORT_SYMBOL(ip_vs_conn_in_get); |
@@ -536,26 +535,6 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
536 | return NF_DROP; | 535 | return NF_DROP; |
537 | } | 536 | } |
538 | 537 | ||
539 | |||
540 | /* | ||
541 | * It is hooked before NF_IP_PRI_NAT_SRC at the NF_INET_POST_ROUTING | ||
542 | * chain, and is used for VS/NAT. | ||
543 | * It detects packets for VS/NAT connections and sends the packets | ||
544 | * immediately. This can avoid that iptable_nat mangles the packets | ||
545 | * for VS/NAT. | ||
546 | */ | ||
547 | static unsigned int ip_vs_post_routing(unsigned int hooknum, | ||
548 | struct sk_buff *skb, | ||
549 | const struct net_device *in, | ||
550 | const struct net_device *out, | ||
551 | int (*okfn)(struct sk_buff *)) | ||
552 | { | ||
553 | if (!skb->ipvs_property) | ||
554 | return NF_ACCEPT; | ||
555 | /* The packet was sent from IPVS, exit this chain */ | ||
556 | return NF_STOP; | ||
557 | } | ||
558 | |||
559 | __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) | 538 | __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) |
560 | { | 539 | { |
561 | return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); | 540 | return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); |
@@ -1499,14 +1478,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | |||
1499 | .hooknum = NF_INET_FORWARD, | 1478 | .hooknum = NF_INET_FORWARD, |
1500 | .priority = 99, | 1479 | .priority = 99, |
1501 | }, | 1480 | }, |
1502 | /* Before the netfilter connection tracking, exit from POST_ROUTING */ | ||
1503 | { | ||
1504 | .hook = ip_vs_post_routing, | ||
1505 | .owner = THIS_MODULE, | ||
1506 | .pf = PF_INET, | ||
1507 | .hooknum = NF_INET_POST_ROUTING, | ||
1508 | .priority = NF_IP_PRI_NAT_SRC-1, | ||
1509 | }, | ||
1510 | #ifdef CONFIG_IP_VS_IPV6 | 1481 | #ifdef CONFIG_IP_VS_IPV6 |
1511 | /* After packet filtering, forward packet through VS/DR, VS/TUN, | 1482 | /* After packet filtering, forward packet through VS/DR, VS/TUN, |
1512 | * or VS/NAT(change destination), so that filtering rules can be | 1483 | * or VS/NAT(change destination), so that filtering rules can be |
@@ -1535,14 +1506,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | |||
1535 | .hooknum = NF_INET_FORWARD, | 1506 | .hooknum = NF_INET_FORWARD, |
1536 | .priority = 99, | 1507 | .priority = 99, |
1537 | }, | 1508 | }, |
1538 | /* Before the netfilter connection tracking, exit from POST_ROUTING */ | ||
1539 | { | ||
1540 | .hook = ip_vs_post_routing, | ||
1541 | .owner = THIS_MODULE, | ||
1542 | .pf = PF_INET6, | ||
1543 | .hooknum = NF_INET_POST_ROUTING, | ||
1544 | .priority = NF_IP6_PRI_NAT_SRC-1, | ||
1545 | }, | ||
1546 | #endif | 1509 | #endif |
1547 | }; | 1510 | }; |
1548 | 1511 | ||
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 2ae747a376a5..f228a17ec649 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c | |||
@@ -20,6 +20,17 @@ | |||
20 | * | 20 | * |
21 | * Author: Wouter Gadeyne | 21 | * Author: Wouter Gadeyne |
22 | * | 22 | * |
23 | * | ||
24 | * Code for ip_vs_expect_related and ip_vs_expect_callback is taken from | ||
25 | * http://www.ssi.bg/~ja/nfct/: | ||
26 | * | ||
27 | * ip_vs_nfct.c: Netfilter connection tracking support for IPVS | ||
28 | * | ||
29 | * Portions Copyright (C) 2001-2002 | ||
30 | * Antefacto Ltd, 181 Parnell St, Dublin 1, Ireland. | ||
31 | * | ||
32 | * Portions Copyright (C) 2003-2008 | ||
33 | * Julian Anastasov | ||
23 | */ | 34 | */ |
24 | 35 | ||
25 | #define KMSG_COMPONENT "IPVS" | 36 | #define KMSG_COMPONENT "IPVS" |
@@ -32,6 +43,9 @@ | |||
32 | #include <linux/in.h> | 43 | #include <linux/in.h> |
33 | #include <linux/ip.h> | 44 | #include <linux/ip.h> |
34 | #include <linux/netfilter.h> | 45 | #include <linux/netfilter.h> |
46 | #include <net/netfilter/nf_conntrack.h> | ||
47 | #include <net/netfilter/nf_conntrack_expect.h> | ||
48 | #include <net/netfilter/nf_nat_helper.h> | ||
35 | #include <linux/gfp.h> | 49 | #include <linux/gfp.h> |
36 | #include <net/protocol.h> | 50 | #include <net/protocol.h> |
37 | #include <net/tcp.h> | 51 | #include <net/tcp.h> |
@@ -43,6 +57,16 @@ | |||
43 | #define SERVER_STRING "227 Entering Passive Mode (" | 57 | #define SERVER_STRING "227 Entering Passive Mode (" |
44 | #define CLIENT_STRING "PORT " | 58 | #define CLIENT_STRING "PORT " |
45 | 59 | ||
60 | #define FMT_TUPLE "%pI4:%u->%pI4:%u/%u" | ||
61 | #define ARG_TUPLE(T) &(T)->src.u3.ip, ntohs((T)->src.u.all), \ | ||
62 | &(T)->dst.u3.ip, ntohs((T)->dst.u.all), \ | ||
63 | (T)->dst.protonum | ||
64 | |||
65 | #define FMT_CONN "%pI4:%u->%pI4:%u->%pI4:%u/%u:%u" | ||
66 | #define ARG_CONN(C) &((C)->caddr.ip), ntohs((C)->cport), \ | ||
67 | &((C)->vaddr.ip), ntohs((C)->vport), \ | ||
68 | &((C)->daddr.ip), ntohs((C)->dport), \ | ||
69 | (C)->protocol, (C)->state | ||
46 | 70 | ||
47 | /* | 71 | /* |
48 | * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper | 72 | * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper |
@@ -123,6 +147,119 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit, | |||
123 | return 1; | 147 | return 1; |
124 | } | 148 | } |
125 | 149 | ||
150 | /* | ||
151 | * Called from init_conntrack() as expectfn handler. | ||
152 | */ | ||
153 | static void | ||
154 | ip_vs_expect_callback(struct nf_conn *ct, | ||
155 | struct nf_conntrack_expect *exp) | ||
156 | { | ||
157 | struct nf_conntrack_tuple *orig, new_reply; | ||
158 | struct ip_vs_conn *cp; | ||
159 | |||
160 | if (exp->tuple.src.l3num != PF_INET) | ||
161 | return; | ||
162 | |||
163 | /* | ||
164 | * We assume that no NF locks are held before this callback. | ||
165 | * ip_vs_conn_out_get and ip_vs_conn_in_get should match their | ||
166 | * expectations even if they use wildcard values, now we provide the | ||
167 | * actual values from the newly created original conntrack direction. | ||
168 | * The conntrack is confirmed when packet reaches IPVS hooks. | ||
169 | */ | ||
170 | |||
171 | /* RS->CLIENT */ | ||
172 | orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
173 | cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum, | ||
174 | &orig->src.u3, orig->src.u.tcp.port, | ||
175 | &orig->dst.u3, orig->dst.u.tcp.port); | ||
176 | if (cp) { | ||
177 | /* Change reply CLIENT->RS to CLIENT->VS */ | ||
178 | new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | ||
179 | IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", " | ||
180 | FMT_TUPLE ", found inout cp=" FMT_CONN "\n", | ||
181 | __func__, ct, ct->status, | ||
182 | ARG_TUPLE(orig), ARG_TUPLE(&new_reply), | ||
183 | ARG_CONN(cp)); | ||
184 | new_reply.dst.u3 = cp->vaddr; | ||
185 | new_reply.dst.u.tcp.port = cp->vport; | ||
186 | IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", " FMT_TUPLE | ||
187 | ", inout cp=" FMT_CONN "\n", | ||
188 | __func__, ct, | ||
189 | ARG_TUPLE(orig), ARG_TUPLE(&new_reply), | ||
190 | ARG_CONN(cp)); | ||
191 | goto alter; | ||
192 | } | ||
193 | |||
194 | /* CLIENT->VS */ | ||
195 | cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum, | ||
196 | &orig->src.u3, orig->src.u.tcp.port, | ||
197 | &orig->dst.u3, orig->dst.u.tcp.port); | ||
198 | if (cp) { | ||
199 | /* Change reply VS->CLIENT to RS->CLIENT */ | ||
200 | new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | ||
201 | IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuples=" FMT_TUPLE ", " | ||
202 | FMT_TUPLE ", found outin cp=" FMT_CONN "\n", | ||
203 | __func__, ct, ct->status, | ||
204 | ARG_TUPLE(orig), ARG_TUPLE(&new_reply), | ||
205 | ARG_CONN(cp)); | ||
206 | new_reply.src.u3 = cp->daddr; | ||
207 | new_reply.src.u.tcp.port = cp->dport; | ||
208 | IP_VS_DBG(7, "%s(): ct=%p, new tuples=" FMT_TUPLE ", " | ||
209 | FMT_TUPLE ", outin cp=" FMT_CONN "\n", | ||
210 | __func__, ct, | ||
211 | ARG_TUPLE(orig), ARG_TUPLE(&new_reply), | ||
212 | ARG_CONN(cp)); | ||
213 | goto alter; | ||
214 | } | ||
215 | |||
216 | IP_VS_DBG(7, "%s(): ct=%p, status=0x%lX, tuple=" FMT_TUPLE | ||
217 | " - unknown expect\n", | ||
218 | __func__, ct, ct->status, ARG_TUPLE(orig)); | ||
219 | return; | ||
220 | |||
221 | alter: | ||
222 | /* Never alter conntrack for non-NAT conns */ | ||
223 | if (IP_VS_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ) | ||
224 | nf_conntrack_alter_reply(ct, &new_reply); | ||
225 | ip_vs_conn_put(cp); | ||
226 | return; | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * Create NF conntrack expectation with wildcard (optional) source port. | ||
231 | * Then the default callback function will alter the reply and will confirm | ||
232 | * the conntrack entry when the first packet comes. | ||
233 | */ | ||
234 | static void | ||
235 | ip_vs_expect_related(struct sk_buff *skb, struct nf_conn *ct, | ||
236 | struct ip_vs_conn *cp, u_int8_t proto, | ||
237 | const __be16 *port, int from_rs) | ||
238 | { | ||
239 | struct nf_conntrack_expect *exp; | ||
240 | |||
241 | BUG_ON(!ct || ct == &nf_conntrack_untracked); | ||
242 | |||
243 | exp = nf_ct_expect_alloc(ct); | ||
244 | if (!exp) | ||
245 | return; | ||
246 | |||
247 | if (from_rs) | ||
248 | nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, | ||
249 | nf_ct_l3num(ct), &cp->daddr, &cp->caddr, | ||
250 | proto, port, &cp->cport); | ||
251 | else | ||
252 | nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, | ||
253 | nf_ct_l3num(ct), &cp->caddr, &cp->vaddr, | ||
254 | proto, port, &cp->vport); | ||
255 | |||
256 | exp->expectfn = ip_vs_expect_callback; | ||
257 | |||
258 | IP_VS_DBG(7, "%s(): ct=%p, expect tuple=" FMT_TUPLE "\n", | ||
259 | __func__, ct, ARG_TUPLE(&exp->tuple)); | ||
260 | nf_ct_expect_related(exp); | ||
261 | nf_ct_expect_put(exp); | ||
262 | } | ||
126 | 263 | ||
127 | /* | 264 | /* |
128 | * Look at outgoing ftp packets to catch the response to a PASV command | 265 | * Look at outgoing ftp packets to catch the response to a PASV command |
@@ -149,7 +286,9 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
149 | struct ip_vs_conn *n_cp; | 286 | struct ip_vs_conn *n_cp; |
150 | char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ | 287 | char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */ |
151 | unsigned buf_len; | 288 | unsigned buf_len; |
152 | int ret; | 289 | int ret = 0; |
290 | enum ip_conntrack_info ctinfo; | ||
291 | struct nf_conn *ct; | ||
153 | 292 | ||
154 | #ifdef CONFIG_IP_VS_IPV6 | 293 | #ifdef CONFIG_IP_VS_IPV6 |
155 | /* This application helper doesn't work with IPv6 yet, | 294 | /* This application helper doesn't work with IPv6 yet, |
@@ -219,19 +358,26 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
219 | 358 | ||
220 | buf_len = strlen(buf); | 359 | buf_len = strlen(buf); |
221 | 360 | ||
361 | ct = nf_ct_get(skb, &ctinfo); | ||
362 | if (ct && !nf_ct_is_untracked(ct)) { | ||
363 | /* If mangling fails this function will return 0 | ||
364 | * which will cause the packet to be dropped. | ||
365 | * Mangling can only fail under memory pressure, | ||
366 | * hopefully it will succeed on the retransmitted | ||
367 | * packet. | ||
368 | */ | ||
369 | ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | ||
370 | start-data, end-start, | ||
371 | buf, buf_len); | ||
372 | if (ret) | ||
373 | ip_vs_expect_related(skb, ct, n_cp, | ||
374 | IPPROTO_TCP, NULL, 0); | ||
375 | } | ||
376 | |||
222 | /* | 377 | /* |
223 | * Calculate required delta-offset to keep TCP happy | 378 | * Not setting 'diff' is intentional, otherwise the sequence |
379 | * would be adjusted twice. | ||
224 | */ | 380 | */ |
225 | *diff = buf_len - (end-start); | ||
226 | |||
227 | if (*diff == 0) { | ||
228 | /* simply replace it with new passive address */ | ||
229 | memcpy(start, buf, buf_len); | ||
230 | ret = 1; | ||
231 | } else { | ||
232 | ret = !ip_vs_skb_replace(skb, GFP_ATOMIC, start, | ||
233 | end-start, buf, buf_len); | ||
234 | } | ||
235 | 381 | ||
236 | cp->app_data = NULL; | 382 | cp->app_data = NULL; |
237 | ip_vs_tcp_conn_listen(n_cp); | 383 | ip_vs_tcp_conn_listen(n_cp); |
@@ -263,6 +409,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
263 | union nf_inet_addr to; | 409 | union nf_inet_addr to; |
264 | __be16 port; | 410 | __be16 port; |
265 | struct ip_vs_conn *n_cp; | 411 | struct ip_vs_conn *n_cp; |
412 | struct nf_conn *ct; | ||
266 | 413 | ||
267 | #ifdef CONFIG_IP_VS_IPV6 | 414 | #ifdef CONFIG_IP_VS_IPV6 |
268 | /* This application helper doesn't work with IPv6 yet, | 415 | /* This application helper doesn't work with IPv6 yet, |
@@ -349,6 +496,11 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
349 | ip_vs_control_add(n_cp, cp); | 496 | ip_vs_control_add(n_cp, cp); |
350 | } | 497 | } |
351 | 498 | ||
499 | ct = (struct nf_conn *)skb->nfct; | ||
500 | if (ct && ct != &nf_conntrack_untracked) | ||
501 | ip_vs_expect_related(skb, ct, n_cp, | ||
502 | IPPROTO_TCP, &n_cp->dport, 1); | ||
503 | |||
352 | /* | 504 | /* |
353 | * Move tunnel to listen state | 505 | * Move tunnel to listen state |
354 | */ | 506 | */ |
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 2d3d5e4b35f8..027f654799fe 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c | |||
@@ -98,6 +98,7 @@ struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto) | |||
98 | 98 | ||
99 | return NULL; | 99 | return NULL; |
100 | } | 100 | } |
101 | EXPORT_SYMBOL(ip_vs_proto_get); | ||
101 | 102 | ||
102 | 103 | ||
103 | /* | 104 | /* |
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index c9a3f7a21d53..4c0855cb006e 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c | |||
@@ -8,55 +8,6 @@ | |||
8 | #include <net/sctp/checksum.h> | 8 | #include <net/sctp/checksum.h> |
9 | #include <net/ip_vs.h> | 9 | #include <net/ip_vs.h> |
10 | 10 | ||
11 | |||
12 | static struct ip_vs_conn * | ||
13 | sctp_conn_in_get(int af, | ||
14 | const struct sk_buff *skb, | ||
15 | struct ip_vs_protocol *pp, | ||
16 | const struct ip_vs_iphdr *iph, | ||
17 | unsigned int proto_off, | ||
18 | int inverse) | ||
19 | { | ||
20 | __be16 _ports[2], *pptr; | ||
21 | |||
22 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
23 | if (pptr == NULL) | ||
24 | return NULL; | ||
25 | |||
26 | if (likely(!inverse)) | ||
27 | return ip_vs_conn_in_get(af, iph->protocol, | ||
28 | &iph->saddr, pptr[0], | ||
29 | &iph->daddr, pptr[1]); | ||
30 | else | ||
31 | return ip_vs_conn_in_get(af, iph->protocol, | ||
32 | &iph->daddr, pptr[1], | ||
33 | &iph->saddr, pptr[0]); | ||
34 | } | ||
35 | |||
36 | static struct ip_vs_conn * | ||
37 | sctp_conn_out_get(int af, | ||
38 | const struct sk_buff *skb, | ||
39 | struct ip_vs_protocol *pp, | ||
40 | const struct ip_vs_iphdr *iph, | ||
41 | unsigned int proto_off, | ||
42 | int inverse) | ||
43 | { | ||
44 | __be16 _ports[2], *pptr; | ||
45 | |||
46 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
47 | if (pptr == NULL) | ||
48 | return NULL; | ||
49 | |||
50 | if (likely(!inverse)) | ||
51 | return ip_vs_conn_out_get(af, iph->protocol, | ||
52 | &iph->saddr, pptr[0], | ||
53 | &iph->daddr, pptr[1]); | ||
54 | else | ||
55 | return ip_vs_conn_out_get(af, iph->protocol, | ||
56 | &iph->daddr, pptr[1], | ||
57 | &iph->saddr, pptr[0]); | ||
58 | } | ||
59 | |||
60 | static int | 11 | static int |
61 | sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, | 12 | sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, |
62 | int *verdict, struct ip_vs_conn **cpp) | 13 | int *verdict, struct ip_vs_conn **cpp) |
@@ -173,7 +124,7 @@ sctp_dnat_handler(struct sk_buff *skb, | |||
173 | return 0; | 124 | return 0; |
174 | 125 | ||
175 | /* Call application helper if needed */ | 126 | /* Call application helper if needed */ |
176 | if (!ip_vs_app_pkt_out(cp, skb)) | 127 | if (!ip_vs_app_pkt_in(cp, skb)) |
177 | return 0; | 128 | return 0; |
178 | } | 129 | } |
179 | 130 | ||
@@ -1169,8 +1120,8 @@ struct ip_vs_protocol ip_vs_protocol_sctp = { | |||
1169 | .register_app = sctp_register_app, | 1120 | .register_app = sctp_register_app, |
1170 | .unregister_app = sctp_unregister_app, | 1121 | .unregister_app = sctp_unregister_app, |
1171 | .conn_schedule = sctp_conn_schedule, | 1122 | .conn_schedule = sctp_conn_schedule, |
1172 | .conn_in_get = sctp_conn_in_get, | 1123 | .conn_in_get = ip_vs_conn_in_get_proto, |
1173 | .conn_out_get = sctp_conn_out_get, | 1124 | .conn_out_get = ip_vs_conn_out_get_proto, |
1174 | .snat_handler = sctp_snat_handler, | 1125 | .snat_handler = sctp_snat_handler, |
1175 | .dnat_handler = sctp_dnat_handler, | 1126 | .dnat_handler = sctp_dnat_handler, |
1176 | .csum_check = sctp_csum_check, | 1127 | .csum_check = sctp_csum_check, |
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index 91d28e073742..282d24de8592 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c | |||
@@ -27,52 +27,6 @@ | |||
27 | 27 | ||
28 | #include <net/ip_vs.h> | 28 | #include <net/ip_vs.h> |
29 | 29 | ||
30 | |||
31 | static struct ip_vs_conn * | ||
32 | tcp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp, | ||
33 | const struct ip_vs_iphdr *iph, unsigned int proto_off, | ||
34 | int inverse) | ||
35 | { | ||
36 | __be16 _ports[2], *pptr; | ||
37 | |||
38 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
39 | if (pptr == NULL) | ||
40 | return NULL; | ||
41 | |||
42 | if (likely(!inverse)) { | ||
43 | return ip_vs_conn_in_get(af, iph->protocol, | ||
44 | &iph->saddr, pptr[0], | ||
45 | &iph->daddr, pptr[1]); | ||
46 | } else { | ||
47 | return ip_vs_conn_in_get(af, iph->protocol, | ||
48 | &iph->daddr, pptr[1], | ||
49 | &iph->saddr, pptr[0]); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | static struct ip_vs_conn * | ||
54 | tcp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp, | ||
55 | const struct ip_vs_iphdr *iph, unsigned int proto_off, | ||
56 | int inverse) | ||
57 | { | ||
58 | __be16 _ports[2], *pptr; | ||
59 | |||
60 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
61 | if (pptr == NULL) | ||
62 | return NULL; | ||
63 | |||
64 | if (likely(!inverse)) { | ||
65 | return ip_vs_conn_out_get(af, iph->protocol, | ||
66 | &iph->saddr, pptr[0], | ||
67 | &iph->daddr, pptr[1]); | ||
68 | } else { | ||
69 | return ip_vs_conn_out_get(af, iph->protocol, | ||
70 | &iph->daddr, pptr[1], | ||
71 | &iph->saddr, pptr[0]); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | |||
76 | static int | 30 | static int |
77 | tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, | 31 | tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, |
78 | int *verdict, struct ip_vs_conn **cpp) | 32 | int *verdict, struct ip_vs_conn **cpp) |
@@ -721,8 +675,8 @@ struct ip_vs_protocol ip_vs_protocol_tcp = { | |||
721 | .register_app = tcp_register_app, | 675 | .register_app = tcp_register_app, |
722 | .unregister_app = tcp_unregister_app, | 676 | .unregister_app = tcp_unregister_app, |
723 | .conn_schedule = tcp_conn_schedule, | 677 | .conn_schedule = tcp_conn_schedule, |
724 | .conn_in_get = tcp_conn_in_get, | 678 | .conn_in_get = ip_vs_conn_in_get_proto, |
725 | .conn_out_get = tcp_conn_out_get, | 679 | .conn_out_get = ip_vs_conn_out_get_proto, |
726 | .snat_handler = tcp_snat_handler, | 680 | .snat_handler = tcp_snat_handler, |
727 | .dnat_handler = tcp_dnat_handler, | 681 | .dnat_handler = tcp_dnat_handler, |
728 | .csum_check = tcp_csum_check, | 682 | .csum_check = tcp_csum_check, |
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index e7a6885e0167..8553231b5d41 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c | |||
@@ -27,58 +27,6 @@ | |||
27 | #include <net/ip.h> | 27 | #include <net/ip.h> |
28 | #include <net/ip6_checksum.h> | 28 | #include <net/ip6_checksum.h> |
29 | 29 | ||
30 | static struct ip_vs_conn * | ||
31 | udp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp, | ||
32 | const struct ip_vs_iphdr *iph, unsigned int proto_off, | ||
33 | int inverse) | ||
34 | { | ||
35 | struct ip_vs_conn *cp; | ||
36 | __be16 _ports[2], *pptr; | ||
37 | |||
38 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
39 | if (pptr == NULL) | ||
40 | return NULL; | ||
41 | |||
42 | if (likely(!inverse)) { | ||
43 | cp = ip_vs_conn_in_get(af, iph->protocol, | ||
44 | &iph->saddr, pptr[0], | ||
45 | &iph->daddr, pptr[1]); | ||
46 | } else { | ||
47 | cp = ip_vs_conn_in_get(af, iph->protocol, | ||
48 | &iph->daddr, pptr[1], | ||
49 | &iph->saddr, pptr[0]); | ||
50 | } | ||
51 | |||
52 | return cp; | ||
53 | } | ||
54 | |||
55 | |||
56 | static struct ip_vs_conn * | ||
57 | udp_conn_out_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp, | ||
58 | const struct ip_vs_iphdr *iph, unsigned int proto_off, | ||
59 | int inverse) | ||
60 | { | ||
61 | struct ip_vs_conn *cp; | ||
62 | __be16 _ports[2], *pptr; | ||
63 | |||
64 | pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports); | ||
65 | if (pptr == NULL) | ||
66 | return NULL; | ||
67 | |||
68 | if (likely(!inverse)) { | ||
69 | cp = ip_vs_conn_out_get(af, iph->protocol, | ||
70 | &iph->saddr, pptr[0], | ||
71 | &iph->daddr, pptr[1]); | ||
72 | } else { | ||
73 | cp = ip_vs_conn_out_get(af, iph->protocol, | ||
74 | &iph->daddr, pptr[1], | ||
75 | &iph->saddr, pptr[0]); | ||
76 | } | ||
77 | |||
78 | return cp; | ||
79 | } | ||
80 | |||
81 | |||
82 | static int | 30 | static int |
83 | udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, | 31 | udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, |
84 | int *verdict, struct ip_vs_conn **cpp) | 32 | int *verdict, struct ip_vs_conn **cpp) |
@@ -520,8 +468,8 @@ struct ip_vs_protocol ip_vs_protocol_udp = { | |||
520 | .init = udp_init, | 468 | .init = udp_init, |
521 | .exit = udp_exit, | 469 | .exit = udp_exit, |
522 | .conn_schedule = udp_conn_schedule, | 470 | .conn_schedule = udp_conn_schedule, |
523 | .conn_in_get = udp_conn_in_get, | 471 | .conn_in_get = ip_vs_conn_in_get_proto, |
524 | .conn_out_get = udp_conn_out_get, | 472 | .conn_out_get = ip_vs_conn_out_get_proto, |
525 | .snat_handler = udp_snat_handler, | 473 | .snat_handler = udp_snat_handler, |
526 | .dnat_handler = udp_dnat_handler, | 474 | .dnat_handler = udp_dnat_handler, |
527 | .csum_check = udp_csum_check, | 475 | .csum_check = udp_csum_check, |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 02b078e11cf3..21e1a5e9b9d3 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <net/ip6_route.h> | 28 | #include <net/ip6_route.h> |
29 | #include <linux/icmpv6.h> | 29 | #include <linux/icmpv6.h> |
30 | #include <linux/netfilter.h> | 30 | #include <linux/netfilter.h> |
31 | #include <net/netfilter/nf_conntrack.h> | ||
31 | #include <linux/netfilter_ipv4.h> | 32 | #include <linux/netfilter_ipv4.h> |
32 | 33 | ||
33 | #include <net/ip_vs.h> | 34 | #include <net/ip_vs.h> |
@@ -348,6 +349,30 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
348 | } | 349 | } |
349 | #endif | 350 | #endif |
350 | 351 | ||
352 | static void | ||
353 | ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp) | ||
354 | { | ||
355 | struct nf_conn *ct = (struct nf_conn *)skb->nfct; | ||
356 | struct nf_conntrack_tuple new_tuple; | ||
357 | |||
358 | if (ct == NULL || nf_ct_is_untracked(ct) || nf_ct_is_confirmed(ct)) | ||
359 | return; | ||
360 | |||
361 | /* | ||
362 | * The connection is not yet in the hashtable, so we update it. | ||
363 | * CIP->VIP will remain the same, so leave the tuple in | ||
364 | * IP_CT_DIR_ORIGINAL untouched. When the reply comes back from the | ||
365 | * real-server we will see RIP->DIP. | ||
366 | */ | ||
367 | new_tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | ||
368 | new_tuple.src.u3 = cp->daddr; | ||
369 | /* | ||
370 | * This will also take care of UDP and other protocols. | ||
371 | */ | ||
372 | new_tuple.src.u.tcp.port = cp->dport; | ||
373 | nf_conntrack_alter_reply(ct, &new_tuple); | ||
374 | } | ||
375 | |||
351 | /* | 376 | /* |
352 | * NAT transmitter (only for outside-to-inside nat forwarding) | 377 | * NAT transmitter (only for outside-to-inside nat forwarding) |
353 | * Not used for related ICMP | 378 | * Not used for related ICMP |
@@ -403,6 +428,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
403 | 428 | ||
404 | IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); | 429 | IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); |
405 | 430 | ||
431 | ip_vs_update_conntrack(skb, cp); | ||
432 | |||
406 | /* FIXME: when application helper enlarges the packet and the length | 433 | /* FIXME: when application helper enlarges the packet and the length |
407 | is larger than the MTU of outgoing device, there will be still | 434 | is larger than the MTU of outgoing device, there will be still |
408 | MTU problem. */ | 435 | MTU problem. */ |
@@ -479,6 +506,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
479 | 506 | ||
480 | IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); | 507 | IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT"); |
481 | 508 | ||
509 | ip_vs_update_conntrack(skb, cp); | ||
510 | |||
482 | /* FIXME: when application helper enlarges the packet and the length | 511 | /* FIXME: when application helper enlarges the packet and the length |
483 | is larger than the MTU of outgoing device, there will be still | 512 | is larger than the MTU of outgoing device, there will be still |
484 | MTU problem. */ | 513 | MTU problem. */ |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 16b41b4e2a3c..df3eedb142ff 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -966,8 +966,7 @@ acct: | |||
966 | if (acct) { | 966 | if (acct) { |
967 | spin_lock_bh(&ct->lock); | 967 | spin_lock_bh(&ct->lock); |
968 | acct[CTINFO2DIR(ctinfo)].packets++; | 968 | acct[CTINFO2DIR(ctinfo)].packets++; |
969 | acct[CTINFO2DIR(ctinfo)].bytes += | 969 | acct[CTINFO2DIR(ctinfo)].bytes += skb->len; |
970 | skb->len - skb_network_offset(skb); | ||
971 | spin_unlock_bh(&ct->lock); | 970 | spin_unlock_bh(&ct->lock); |
972 | } | 971 | } |
973 | } | 972 | } |
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index fdc8fb4ae10f..7dcf7a404190 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c | |||
@@ -23,9 +23,10 @@ void __nf_ct_ext_destroy(struct nf_conn *ct) | |||
23 | { | 23 | { |
24 | unsigned int i; | 24 | unsigned int i; |
25 | struct nf_ct_ext_type *t; | 25 | struct nf_ct_ext_type *t; |
26 | struct nf_ct_ext *ext = ct->ext; | ||
26 | 27 | ||
27 | for (i = 0; i < NF_CT_EXT_NUM; i++) { | 28 | for (i = 0; i < NF_CT_EXT_NUM; i++) { |
28 | if (!nf_ct_ext_exist(ct, i)) | 29 | if (!__nf_ct_ext_exist(ext, i)) |
29 | continue; | 30 | continue; |
30 | 31 | ||
31 | rcu_read_lock(); | 32 | rcu_read_lock(); |
@@ -73,44 +74,45 @@ static void __nf_ct_ext_free_rcu(struct rcu_head *head) | |||
73 | 74 | ||
74 | void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) | 75 | void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) |
75 | { | 76 | { |
76 | struct nf_ct_ext *new; | 77 | struct nf_ct_ext *old, *new; |
77 | int i, newlen, newoff; | 78 | int i, newlen, newoff; |
78 | struct nf_ct_ext_type *t; | 79 | struct nf_ct_ext_type *t; |
79 | 80 | ||
80 | /* Conntrack must not be confirmed to avoid races on reallocation. */ | 81 | /* Conntrack must not be confirmed to avoid races on reallocation. */ |
81 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); | 82 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); |
82 | 83 | ||
83 | if (!ct->ext) | 84 | old = ct->ext; |
85 | if (!old) | ||
84 | return nf_ct_ext_create(&ct->ext, id, gfp); | 86 | return nf_ct_ext_create(&ct->ext, id, gfp); |
85 | 87 | ||
86 | if (nf_ct_ext_exist(ct, id)) | 88 | if (__nf_ct_ext_exist(old, id)) |
87 | return NULL; | 89 | return NULL; |
88 | 90 | ||
89 | rcu_read_lock(); | 91 | rcu_read_lock(); |
90 | t = rcu_dereference(nf_ct_ext_types[id]); | 92 | t = rcu_dereference(nf_ct_ext_types[id]); |
91 | BUG_ON(t == NULL); | 93 | BUG_ON(t == NULL); |
92 | 94 | ||
93 | newoff = ALIGN(ct->ext->len, t->align); | 95 | newoff = ALIGN(old->len, t->align); |
94 | newlen = newoff + t->len; | 96 | newlen = newoff + t->len; |
95 | rcu_read_unlock(); | 97 | rcu_read_unlock(); |
96 | 98 | ||
97 | new = __krealloc(ct->ext, newlen, gfp); | 99 | new = __krealloc(old, newlen, gfp); |
98 | if (!new) | 100 | if (!new) |
99 | return NULL; | 101 | return NULL; |
100 | 102 | ||
101 | if (new != ct->ext) { | 103 | if (new != old) { |
102 | for (i = 0; i < NF_CT_EXT_NUM; i++) { | 104 | for (i = 0; i < NF_CT_EXT_NUM; i++) { |
103 | if (!nf_ct_ext_exist(ct, i)) | 105 | if (!__nf_ct_ext_exist(old, i)) |
104 | continue; | 106 | continue; |
105 | 107 | ||
106 | rcu_read_lock(); | 108 | rcu_read_lock(); |
107 | t = rcu_dereference(nf_ct_ext_types[i]); | 109 | t = rcu_dereference(nf_ct_ext_types[i]); |
108 | if (t && t->move) | 110 | if (t && t->move) |
109 | t->move((void *)new + new->offset[i], | 111 | t->move((void *)new + new->offset[i], |
110 | (void *)ct->ext + ct->ext->offset[i]); | 112 | (void *)old + old->offset[i]); |
111 | rcu_read_unlock(); | 113 | rcu_read_unlock(); |
112 | } | 114 | } |
113 | call_rcu(&ct->ext->rcu, __nf_ct_ext_free_rcu); | 115 | call_rcu(&old->rcu, __nf_ct_ext_free_rcu); |
114 | ct->ext = new; | 116 | ct->ext = new; |
115 | } | 117 | } |
116 | 118 | ||
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 802dbffae8b4..c4c885dca3bd 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -585,8 +585,16 @@ static bool tcp_in_window(const struct nf_conn *ct, | |||
585 | * Let's try to use the data from the packet. | 585 | * Let's try to use the data from the packet. |
586 | */ | 586 | */ |
587 | sender->td_end = end; | 587 | sender->td_end = end; |
588 | win <<= sender->td_scale; | ||
588 | sender->td_maxwin = (win == 0 ? 1 : win); | 589 | sender->td_maxwin = (win == 0 ? 1 : win); |
589 | sender->td_maxend = end + sender->td_maxwin; | 590 | sender->td_maxend = end + sender->td_maxwin; |
591 | /* | ||
592 | * We haven't seen traffic in the other direction yet | ||
593 | * but we have to tweak window tracking to pass III | ||
594 | * and IV until that happens. | ||
595 | */ | ||
596 | if (receiver->td_maxwin == 0) | ||
597 | receiver->td_end = receiver->td_maxend = sack; | ||
590 | } | 598 | } |
591 | } else if (((state->state == TCP_CONNTRACK_SYN_SENT | 599 | } else if (((state->state == TCP_CONNTRACK_SYN_SENT |
592 | && dir == IP_CT_DIR_ORIGINAL) | 600 | && dir == IP_CT_DIR_ORIGINAL) |
@@ -680,7 +688,7 @@ static bool tcp_in_window(const struct nf_conn *ct, | |||
680 | /* | 688 | /* |
681 | * Update receiver data. | 689 | * Update receiver data. |
682 | */ | 690 | */ |
683 | if (after(end, sender->td_maxend)) | 691 | if (receiver->td_maxwin != 0 && after(end, sender->td_maxend)) |
684 | receiver->td_maxwin += end - sender->td_maxend; | 692 | receiver->td_maxwin += end - sender->td_maxend; |
685 | if (after(sack + win, receiver->td_maxend - 1)) { | 693 | if (after(sack + win, receiver->td_maxend - 1)) { |
686 | receiver->td_maxend = sack + win; | 694 | receiver->td_maxend = sack + win; |
diff --git a/net/netfilter/xt_CHECKSUM.c b/net/netfilter/xt_CHECKSUM.c new file mode 100644 index 000000000000..0f642ef8cd26 --- /dev/null +++ b/net/netfilter/xt_CHECKSUM.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* iptables module for the packet checksum mangling | ||
2 | * | ||
3 | * (C) 2002 by Harald Welte <laforge@netfilter.org> | ||
4 | * (C) 2010 Red Hat, Inc. | ||
5 | * | ||
6 | * Author: Michael S. Tsirkin <mst@redhat.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | |||
16 | #include <linux/netfilter/x_tables.h> | ||
17 | #include <linux/netfilter/xt_CHECKSUM.h> | ||
18 | |||
19 | MODULE_LICENSE("GPL"); | ||
20 | MODULE_AUTHOR("Michael S. Tsirkin <mst@redhat.com>"); | ||
21 | MODULE_DESCRIPTION("Xtables: checksum modification"); | ||
22 | MODULE_ALIAS("ipt_CHECKSUM"); | ||
23 | MODULE_ALIAS("ip6t_CHECKSUM"); | ||
24 | |||
25 | static unsigned int | ||
26 | checksum_tg(struct sk_buff *skb, const struct xt_action_param *par) | ||
27 | { | ||
28 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
29 | skb_checksum_help(skb); | ||
30 | |||
31 | return XT_CONTINUE; | ||
32 | } | ||
33 | |||
34 | static int checksum_tg_check(const struct xt_tgchk_param *par) | ||
35 | { | ||
36 | const struct xt_CHECKSUM_info *einfo = par->targinfo; | ||
37 | |||
38 | if (einfo->operation & ~XT_CHECKSUM_OP_FILL) { | ||
39 | pr_info("unsupported CHECKSUM operation %x\n", einfo->operation); | ||
40 | return -EINVAL; | ||
41 | } | ||
42 | if (!einfo->operation) { | ||
43 | pr_info("no CHECKSUM operation enabled\n"); | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static struct xt_target checksum_tg_reg __read_mostly = { | ||
50 | .name = "CHECKSUM", | ||
51 | .family = NFPROTO_UNSPEC, | ||
52 | .target = checksum_tg, | ||
53 | .targetsize = sizeof(struct xt_CHECKSUM_info), | ||
54 | .table = "mangle", | ||
55 | .checkentry = checksum_tg_check, | ||
56 | .me = THIS_MODULE, | ||
57 | }; | ||
58 | |||
59 | static int __init checksum_tg_init(void) | ||
60 | { | ||
61 | return xt_register_target(&checksum_tg_reg); | ||
62 | } | ||
63 | |||
64 | static void __exit checksum_tg_exit(void) | ||
65 | { | ||
66 | xt_unregister_target(&checksum_tg_reg); | ||
67 | } | ||
68 | |||
69 | module_init(checksum_tg_init); | ||
70 | module_exit(checksum_tg_exit); | ||
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index e1a0dedac258..c61294d85fda 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
@@ -37,8 +37,10 @@ tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par) | |||
37 | return NF_DROP; | 37 | return NF_DROP; |
38 | 38 | ||
39 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, | 39 | sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, |
40 | iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr, | 40 | iph->saddr, |
41 | hp->source, tgi->lport ? tgi->lport : hp->dest, | 41 | tgi->laddr ? tgi->laddr : iph->daddr, |
42 | hp->source, | ||
43 | tgi->lport ? tgi->lport : hp->dest, | ||
42 | par->in, true); | 44 | par->in, true); |
43 | 45 | ||
44 | /* NOTE: assign_sock consumes our sk reference */ | 46 | /* NOTE: assign_sock consumes our sk reference */ |
diff --git a/net/netfilter/xt_cpu.c b/net/netfilter/xt_cpu.c new file mode 100644 index 000000000000..b39db8a5cbae --- /dev/null +++ b/net/netfilter/xt_cpu.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* Kernel module to match running CPU */ | ||
2 | |||
3 | /* | ||
4 | * Might be used to distribute connections on several daemons, if | ||
5 | * RPS (Remote Packet Steering) is enabled or NIC is multiqueue capable, | ||
6 | * each RX queue IRQ affined to one CPU (1:1 mapping) | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | /* (C) 2010 Eric Dumazet | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/skbuff.h> | ||
19 | #include <linux/netfilter/xt_cpu.h> | ||
20 | #include <linux/netfilter/x_tables.h> | ||
21 | |||
22 | MODULE_LICENSE("GPL"); | ||
23 | MODULE_AUTHOR("Eric Dumazet <eric.dumazet@gmail.com>"); | ||
24 | MODULE_DESCRIPTION("Xtables: CPU match"); | ||
25 | |||
26 | static int cpu_mt_check(const struct xt_mtchk_param *par) | ||
27 | { | ||
28 | const struct xt_cpu_info *info = par->matchinfo; | ||
29 | |||
30 | if (info->invert & ~1) | ||
31 | return -EINVAL; | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static bool cpu_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
36 | { | ||
37 | const struct xt_cpu_info *info = par->matchinfo; | ||
38 | |||
39 | return (info->cpu == smp_processor_id()) ^ info->invert; | ||
40 | } | ||
41 | |||
42 | static struct xt_match cpu_mt_reg __read_mostly = { | ||
43 | .name = "cpu", | ||
44 | .revision = 0, | ||
45 | .family = NFPROTO_UNSPEC, | ||
46 | .checkentry = cpu_mt_check, | ||
47 | .match = cpu_mt, | ||
48 | .matchsize = sizeof(struct xt_cpu_info), | ||
49 | .me = THIS_MODULE, | ||
50 | }; | ||
51 | |||
52 | static int __init cpu_mt_init(void) | ||
53 | { | ||
54 | return xt_register_match(&cpu_mt_reg); | ||
55 | } | ||
56 | |||
57 | static void __exit cpu_mt_exit(void) | ||
58 | { | ||
59 | xt_unregister_match(&cpu_mt_reg); | ||
60 | } | ||
61 | |||
62 | module_init(cpu_mt_init); | ||
63 | module_exit(cpu_mt_exit); | ||
diff --git a/net/netfilter/xt_ipvs.c b/net/netfilter/xt_ipvs.c new file mode 100644 index 000000000000..7a4d66db95ae --- /dev/null +++ b/net/netfilter/xt_ipvs.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * xt_ipvs - kernel module to match IPVS connection properties | ||
3 | * | ||
4 | * Author: Hannes Eder <heder@google.com> | ||
5 | */ | ||
6 | |||
7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/moduleparam.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #ifdef CONFIG_IP_VS_IPV6 | ||
14 | #include <net/ipv6.h> | ||
15 | #endif | ||
16 | #include <linux/ip_vs.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/netfilter/x_tables.h> | ||
19 | #include <linux/netfilter/x_tables.h> | ||
20 | #include <linux/netfilter/xt_ipvs.h> | ||
21 | #include <net/netfilter/nf_conntrack.h> | ||
22 | |||
23 | #include <net/ip_vs.h> | ||
24 | |||
25 | MODULE_AUTHOR("Hannes Eder <heder@google.com>"); | ||
26 | MODULE_DESCRIPTION("Xtables: match IPVS connection properties"); | ||
27 | MODULE_LICENSE("GPL"); | ||
28 | MODULE_ALIAS("ipt_ipvs"); | ||
29 | MODULE_ALIAS("ip6t_ipvs"); | ||
30 | |||
31 | /* borrowed from xt_conntrack */ | ||
32 | static bool ipvs_mt_addrcmp(const union nf_inet_addr *kaddr, | ||
33 | const union nf_inet_addr *uaddr, | ||
34 | const union nf_inet_addr *umask, | ||
35 | unsigned int l3proto) | ||
36 | { | ||
37 | if (l3proto == NFPROTO_IPV4) | ||
38 | return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0; | ||
39 | #ifdef CONFIG_IP_VS_IPV6 | ||
40 | else if (l3proto == NFPROTO_IPV6) | ||
41 | return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6, | ||
42 | &uaddr->in6) == 0; | ||
43 | #endif | ||
44 | else | ||
45 | return false; | ||
46 | } | ||
47 | |||
48 | static bool | ||
49 | ipvs_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
50 | { | ||
51 | const struct xt_ipvs_mtinfo *data = par->matchinfo; | ||
52 | /* ipvs_mt_check ensures that family is only NFPROTO_IPV[46]. */ | ||
53 | const u_int8_t family = par->family; | ||
54 | struct ip_vs_iphdr iph; | ||
55 | struct ip_vs_protocol *pp; | ||
56 | struct ip_vs_conn *cp; | ||
57 | bool match = true; | ||
58 | |||
59 | if (data->bitmask == XT_IPVS_IPVS_PROPERTY) { | ||
60 | match = skb->ipvs_property ^ | ||
61 | !!(data->invert & XT_IPVS_IPVS_PROPERTY); | ||
62 | goto out; | ||
63 | } | ||
64 | |||
65 | /* other flags than XT_IPVS_IPVS_PROPERTY are set */ | ||
66 | if (!skb->ipvs_property) { | ||
67 | match = false; | ||
68 | goto out; | ||
69 | } | ||
70 | |||
71 | ip_vs_fill_iphdr(family, skb_network_header(skb), &iph); | ||
72 | |||
73 | if (data->bitmask & XT_IPVS_PROTO) | ||
74 | if ((iph.protocol == data->l4proto) ^ | ||
75 | !(data->invert & XT_IPVS_PROTO)) { | ||
76 | match = false; | ||
77 | goto out; | ||
78 | } | ||
79 | |||
80 | pp = ip_vs_proto_get(iph.protocol); | ||
81 | if (unlikely(!pp)) { | ||
82 | match = false; | ||
83 | goto out; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Check if the packet belongs to an existing entry | ||
88 | */ | ||
89 | cp = pp->conn_out_get(family, skb, pp, &iph, iph.len, 1 /* inverse */); | ||
90 | if (unlikely(cp == NULL)) { | ||
91 | match = false; | ||
92 | goto out; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * We found a connection, i.e. ct != 0, make sure to call | ||
97 | * __ip_vs_conn_put before returning. In our case jump to out_put_con. | ||
98 | */ | ||
99 | |||
100 | if (data->bitmask & XT_IPVS_VPORT) | ||
101 | if ((cp->vport == data->vport) ^ | ||
102 | !(data->invert & XT_IPVS_VPORT)) { | ||
103 | match = false; | ||
104 | goto out_put_cp; | ||
105 | } | ||
106 | |||
107 | if (data->bitmask & XT_IPVS_VPORTCTL) | ||
108 | if ((cp->control != NULL && | ||
109 | cp->control->vport == data->vportctl) ^ | ||
110 | !(data->invert & XT_IPVS_VPORTCTL)) { | ||
111 | match = false; | ||
112 | goto out_put_cp; | ||
113 | } | ||
114 | |||
115 | if (data->bitmask & XT_IPVS_DIR) { | ||
116 | enum ip_conntrack_info ctinfo; | ||
117 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
118 | |||
119 | if (ct == NULL || nf_ct_is_untracked(ct)) { | ||
120 | match = false; | ||
121 | goto out_put_cp; | ||
122 | } | ||
123 | |||
124 | if ((ctinfo >= IP_CT_IS_REPLY) ^ | ||
125 | !!(data->invert & XT_IPVS_DIR)) { | ||
126 | match = false; | ||
127 | goto out_put_cp; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (data->bitmask & XT_IPVS_METHOD) | ||
132 | if (((cp->flags & IP_VS_CONN_F_FWD_MASK) == data->fwd_method) ^ | ||
133 | !(data->invert & XT_IPVS_METHOD)) { | ||
134 | match = false; | ||
135 | goto out_put_cp; | ||
136 | } | ||
137 | |||
138 | if (data->bitmask & XT_IPVS_VADDR) { | ||
139 | if (ipvs_mt_addrcmp(&cp->vaddr, &data->vaddr, | ||
140 | &data->vmask, family) ^ | ||
141 | !(data->invert & XT_IPVS_VADDR)) { | ||
142 | match = false; | ||
143 | goto out_put_cp; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | out_put_cp: | ||
148 | __ip_vs_conn_put(cp); | ||
149 | out: | ||
150 | pr_debug("match=%d\n", match); | ||
151 | return match; | ||
152 | } | ||
153 | |||
154 | static int ipvs_mt_check(const struct xt_mtchk_param *par) | ||
155 | { | ||
156 | if (par->family != NFPROTO_IPV4 | ||
157 | #ifdef CONFIG_IP_VS_IPV6 | ||
158 | && par->family != NFPROTO_IPV6 | ||
159 | #endif | ||
160 | ) { | ||
161 | pr_info("protocol family %u not supported\n", par->family); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static struct xt_match xt_ipvs_mt_reg __read_mostly = { | ||
169 | .name = "ipvs", | ||
170 | .revision = 0, | ||
171 | .family = NFPROTO_UNSPEC, | ||
172 | .match = ipvs_mt, | ||
173 | .checkentry = ipvs_mt_check, | ||
174 | .matchsize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)), | ||
175 | .me = THIS_MODULE, | ||
176 | }; | ||
177 | |||
178 | static int __init ipvs_mt_init(void) | ||
179 | { | ||
180 | return xt_register_match(&xt_ipvs_mt_reg); | ||
181 | } | ||
182 | |||
183 | static void __exit ipvs_mt_exit(void) | ||
184 | { | ||
185 | xt_unregister_match(&xt_ipvs_mt_reg); | ||
186 | } | ||
187 | |||
188 | module_init(ipvs_mt_init); | ||
189 | module_exit(ipvs_mt_exit); | ||
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index b4f7dfea5980..70eb2b4984dd 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c | |||
@@ -11,7 +11,8 @@ | |||
11 | #include <linux/netfilter/xt_quota.h> | 11 | #include <linux/netfilter/xt_quota.h> |
12 | 12 | ||
13 | struct xt_quota_priv { | 13 | struct xt_quota_priv { |
14 | uint64_t quota; | 14 | spinlock_t lock; |
15 | uint64_t quota; | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | MODULE_LICENSE("GPL"); | 18 | MODULE_LICENSE("GPL"); |
@@ -20,8 +21,6 @@ MODULE_DESCRIPTION("Xtables: countdown quota match"); | |||
20 | MODULE_ALIAS("ipt_quota"); | 21 | MODULE_ALIAS("ipt_quota"); |
21 | MODULE_ALIAS("ip6t_quota"); | 22 | MODULE_ALIAS("ip6t_quota"); |
22 | 23 | ||
23 | static DEFINE_SPINLOCK(quota_lock); | ||
24 | |||
25 | static bool | 24 | static bool |
26 | quota_mt(const struct sk_buff *skb, struct xt_action_param *par) | 25 | quota_mt(const struct sk_buff *skb, struct xt_action_param *par) |
27 | { | 26 | { |
@@ -29,7 +28,7 @@ quota_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
29 | struct xt_quota_priv *priv = q->master; | 28 | struct xt_quota_priv *priv = q->master; |
30 | bool ret = q->flags & XT_QUOTA_INVERT; | 29 | bool ret = q->flags & XT_QUOTA_INVERT; |
31 | 30 | ||
32 | spin_lock_bh("a_lock); | 31 | spin_lock_bh(&priv->lock); |
33 | if (priv->quota >= skb->len) { | 32 | if (priv->quota >= skb->len) { |
34 | priv->quota -= skb->len; | 33 | priv->quota -= skb->len; |
35 | ret = !ret; | 34 | ret = !ret; |
@@ -37,9 +36,7 @@ quota_mt(const struct sk_buff *skb, struct xt_action_param *par) | |||
37 | /* we do not allow even small packets from now on */ | 36 | /* we do not allow even small packets from now on */ |
38 | priv->quota = 0; | 37 | priv->quota = 0; |
39 | } | 38 | } |
40 | /* Copy quota back to matchinfo so that iptables can display it */ | 39 | spin_unlock_bh(&priv->lock); |
41 | q->quota = priv->quota; | ||
42 | spin_unlock_bh("a_lock); | ||
43 | 40 | ||
44 | return ret; | 41 | return ret; |
45 | } | 42 | } |
@@ -55,6 +52,7 @@ static int quota_mt_check(const struct xt_mtchk_param *par) | |||
55 | if (q->master == NULL) | 52 | if (q->master == NULL) |
56 | return -ENOMEM; | 53 | return -ENOMEM; |
57 | 54 | ||
55 | spin_lock_init(&q->master->lock); | ||
58 | q->master->quota = q->quota; | 56 | q->master->quota = q->quota; |
59 | return 0; | 57 | return 0; |
60 | } | 58 | } |
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8648a9922aab..2cbf380377d5 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1406,7 +1406,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1406 | struct netlink_sock *nlk = nlk_sk(sk); | 1406 | struct netlink_sock *nlk = nlk_sk(sk); |
1407 | int noblock = flags&MSG_DONTWAIT; | 1407 | int noblock = flags&MSG_DONTWAIT; |
1408 | size_t copied; | 1408 | size_t copied; |
1409 | struct sk_buff *skb, *frag __maybe_unused = NULL; | 1409 | struct sk_buff *skb; |
1410 | int err; | 1410 | int err; |
1411 | 1411 | ||
1412 | if (flags&MSG_OOB) | 1412 | if (flags&MSG_OOB) |
@@ -1441,7 +1441,21 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1441 | kfree_skb(skb); | 1441 | kfree_skb(skb); |
1442 | skb = compskb; | 1442 | skb = compskb; |
1443 | } else { | 1443 | } else { |
1444 | frag = skb_shinfo(skb)->frag_list; | 1444 | /* |
1445 | * Before setting frag_list to NULL, we must get a | ||
1446 | * private copy of skb if shared (because of MSG_PEEK) | ||
1447 | */ | ||
1448 | if (skb_shared(skb)) { | ||
1449 | struct sk_buff *nskb; | ||
1450 | |||
1451 | nskb = pskb_copy(skb, GFP_KERNEL); | ||
1452 | kfree_skb(skb); | ||
1453 | skb = nskb; | ||
1454 | err = -ENOMEM; | ||
1455 | if (!skb) | ||
1456 | goto out; | ||
1457 | } | ||
1458 | kfree_skb(skb_shinfo(skb)->frag_list); | ||
1445 | skb_shinfo(skb)->frag_list = NULL; | 1459 | skb_shinfo(skb)->frag_list = NULL; |
1446 | } | 1460 | } |
1447 | } | 1461 | } |
@@ -1478,10 +1492,6 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
1478 | if (flags & MSG_TRUNC) | 1492 | if (flags & MSG_TRUNC) |
1479 | copied = skb->len; | 1493 | copied = skb->len; |
1480 | 1494 | ||
1481 | #ifdef CONFIG_COMPAT_NETLINK_MESSAGES | ||
1482 | skb_shinfo(skb)->frag_list = frag; | ||
1483 | #endif | ||
1484 | |||
1485 | skb_free_datagram(sk, skb); | 1495 | skb_free_datagram(sk, skb); |
1486 | 1496 | ||
1487 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) | 1497 | if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index aa4308afcc7f..26ed3e8587c2 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -303,6 +303,7 @@ int genl_register_ops(struct genl_family *family, struct genl_ops *ops) | |||
303 | errout: | 303 | errout: |
304 | return err; | 304 | return err; |
305 | } | 305 | } |
306 | EXPORT_SYMBOL(genl_register_ops); | ||
306 | 307 | ||
307 | /** | 308 | /** |
308 | * genl_unregister_ops - unregister generic netlink operations | 309 | * genl_unregister_ops - unregister generic netlink operations |
@@ -337,6 +338,7 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops) | |||
337 | 338 | ||
338 | return -ENOENT; | 339 | return -ENOENT; |
339 | } | 340 | } |
341 | EXPORT_SYMBOL(genl_unregister_ops); | ||
340 | 342 | ||
341 | /** | 343 | /** |
342 | * genl_register_family - register a generic netlink family | 344 | * genl_register_family - register a generic netlink family |
@@ -405,6 +407,7 @@ errout_locked: | |||
405 | errout: | 407 | errout: |
406 | return err; | 408 | return err; |
407 | } | 409 | } |
410 | EXPORT_SYMBOL(genl_register_family); | ||
408 | 411 | ||
409 | /** | 412 | /** |
410 | * genl_register_family_with_ops - register a generic netlink family | 413 | * genl_register_family_with_ops - register a generic netlink family |
@@ -485,6 +488,7 @@ int genl_unregister_family(struct genl_family *family) | |||
485 | 488 | ||
486 | return -ENOENT; | 489 | return -ENOENT; |
487 | } | 490 | } |
491 | EXPORT_SYMBOL(genl_unregister_family); | ||
488 | 492 | ||
489 | static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 493 | static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
490 | { | 494 | { |
@@ -873,11 +877,7 @@ static int __init genl_init(void) | |||
873 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) | 877 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) |
874 | INIT_LIST_HEAD(&family_ht[i]); | 878 | INIT_LIST_HEAD(&family_ht[i]); |
875 | 879 | ||
876 | err = genl_register_family(&genl_ctrl); | 880 | err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1); |
877 | if (err < 0) | ||
878 | goto problem; | ||
879 | |||
880 | err = genl_register_ops(&genl_ctrl, &genl_ctrl_ops); | ||
881 | if (err < 0) | 881 | if (err < 0) |
882 | goto problem; | 882 | goto problem; |
883 | 883 | ||
@@ -899,11 +899,6 @@ problem: | |||
899 | 899 | ||
900 | subsys_initcall(genl_init); | 900 | subsys_initcall(genl_init); |
901 | 901 | ||
902 | EXPORT_SYMBOL(genl_register_ops); | ||
903 | EXPORT_SYMBOL(genl_unregister_ops); | ||
904 | EXPORT_SYMBOL(genl_register_family); | ||
905 | EXPORT_SYMBOL(genl_unregister_family); | ||
906 | |||
907 | static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group, | 902 | static int genlmsg_mcast(struct sk_buff *skb, u32 pid, unsigned long group, |
908 | gfp_t flags) | 903 | gfp_t flags) |
909 | { | 904 | { |
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index cbc244a128bd..b4fdaac233f7 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c | |||
@@ -109,7 +109,9 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, | |||
109 | init_timer(&rose_neigh->t0timer); | 109 | init_timer(&rose_neigh->t0timer); |
110 | 110 | ||
111 | if (rose_route->ndigis != 0) { | 111 | if (rose_route->ndigis != 0) { |
112 | if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) { | 112 | rose_neigh->digipeat = |
113 | kmalloc(sizeof(ax25_digi), GFP_ATOMIC); | ||
114 | if (rose_neigh->digipeat == NULL) { | ||
113 | kfree(rose_neigh); | 115 | kfree(rose_neigh); |
114 | res = -ENOMEM; | 116 | res = -ENOMEM; |
115 | goto out; | 117 | goto out; |
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index a16b0175f890..11f195af2da0 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c | |||
@@ -33,6 +33,7 @@ | |||
33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; | 33 | static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1]; |
34 | static u32 mirred_idx_gen; | 34 | static u32 mirred_idx_gen; |
35 | static DEFINE_RWLOCK(mirred_lock); | 35 | static DEFINE_RWLOCK(mirred_lock); |
36 | static LIST_HEAD(mirred_list); | ||
36 | 37 | ||
37 | static struct tcf_hashinfo mirred_hash_info = { | 38 | static struct tcf_hashinfo mirred_hash_info = { |
38 | .htab = tcf_mirred_ht, | 39 | .htab = tcf_mirred_ht, |
@@ -47,7 +48,9 @@ static inline int tcf_mirred_release(struct tcf_mirred *m, int bind) | |||
47 | m->tcf_bindcnt--; | 48 | m->tcf_bindcnt--; |
48 | m->tcf_refcnt--; | 49 | m->tcf_refcnt--; |
49 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { | 50 | if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) { |
50 | dev_put(m->tcfm_dev); | 51 | list_del(&m->tcfm_list); |
52 | if (m->tcfm_dev) | ||
53 | dev_put(m->tcfm_dev); | ||
51 | tcf_hash_destroy(&m->common, &mirred_hash_info); | 54 | tcf_hash_destroy(&m->common, &mirred_hash_info); |
52 | return 1; | 55 | return 1; |
53 | } | 56 | } |
@@ -134,8 +137,10 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, | |||
134 | m->tcfm_ok_push = ok_push; | 137 | m->tcfm_ok_push = ok_push; |
135 | } | 138 | } |
136 | spin_unlock_bh(&m->tcf_lock); | 139 | spin_unlock_bh(&m->tcf_lock); |
137 | if (ret == ACT_P_CREATED) | 140 | if (ret == ACT_P_CREATED) { |
141 | list_add(&m->tcfm_list, &mirred_list); | ||
138 | tcf_hash_insert(pc, &mirred_hash_info); | 142 | tcf_hash_insert(pc, &mirred_hash_info); |
143 | } | ||
139 | 144 | ||
140 | return ret; | 145 | return ret; |
141 | } | 146 | } |
@@ -164,9 +169,14 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a, | |||
164 | m->tcf_bstats.packets++; | 169 | m->tcf_bstats.packets++; |
165 | 170 | ||
166 | dev = m->tcfm_dev; | 171 | dev = m->tcfm_dev; |
172 | if (!dev) { | ||
173 | printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); | ||
174 | goto out; | ||
175 | } | ||
176 | |||
167 | if (!(dev->flags & IFF_UP)) { | 177 | if (!(dev->flags & IFF_UP)) { |
168 | if (net_ratelimit()) | 178 | if (net_ratelimit()) |
169 | pr_notice("tc mirred to Houston: device %s is gone!\n", | 179 | pr_notice("tc mirred to Houston: device %s is down\n", |
170 | dev->name); | 180 | dev->name); |
171 | goto out; | 181 | goto out; |
172 | } | 182 | } |
@@ -230,6 +240,28 @@ nla_put_failure: | |||
230 | return -1; | 240 | return -1; |
231 | } | 241 | } |
232 | 242 | ||
243 | static int mirred_device_event(struct notifier_block *unused, | ||
244 | unsigned long event, void *ptr) | ||
245 | { | ||
246 | struct net_device *dev = ptr; | ||
247 | struct tcf_mirred *m; | ||
248 | |||
249 | if (event == NETDEV_UNREGISTER) | ||
250 | list_for_each_entry(m, &mirred_list, tcfm_list) { | ||
251 | if (m->tcfm_dev == dev) { | ||
252 | dev_put(dev); | ||
253 | m->tcfm_dev = NULL; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | return NOTIFY_DONE; | ||
258 | } | ||
259 | |||
260 | static struct notifier_block mirred_device_notifier = { | ||
261 | .notifier_call = mirred_device_event, | ||
262 | }; | ||
263 | |||
264 | |||
233 | static struct tc_action_ops act_mirred_ops = { | 265 | static struct tc_action_ops act_mirred_ops = { |
234 | .kind = "mirred", | 266 | .kind = "mirred", |
235 | .hinfo = &mirred_hash_info, | 267 | .hinfo = &mirred_hash_info, |
@@ -250,12 +282,17 @@ MODULE_LICENSE("GPL"); | |||
250 | 282 | ||
251 | static int __init mirred_init_module(void) | 283 | static int __init mirred_init_module(void) |
252 | { | 284 | { |
285 | int err = register_netdevice_notifier(&mirred_device_notifier); | ||
286 | if (err) | ||
287 | return err; | ||
288 | |||
253 | pr_info("Mirror/redirect action on\n"); | 289 | pr_info("Mirror/redirect action on\n"); |
254 | return tcf_register_action(&act_mirred_ops); | 290 | return tcf_register_action(&act_mirred_ops); |
255 | } | 291 | } |
256 | 292 | ||
257 | static void __exit mirred_cleanup_module(void) | 293 | static void __exit mirred_cleanup_module(void) |
258 | { | 294 | { |
295 | unregister_netdevice_notifier(&mirred_device_notifier); | ||
259 | tcf_unregister_action(&act_mirred_ops); | 296 | tcf_unregister_action(&act_mirred_ops); |
260 | } | 297 | } |
261 | 298 | ||
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 24e614c495f2..d0386a413e8d 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c | |||
@@ -218,6 +218,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
218 | if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph))) | 218 | if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph))) |
219 | goto drop; | 219 | goto drop; |
220 | 220 | ||
221 | icmph = (void *)(skb_network_header(skb) + ihl); | ||
221 | iph = (void *)(icmph + 1); | 222 | iph = (void *)(icmph + 1); |
222 | if (egress) | 223 | if (egress) |
223 | addr = iph->daddr; | 224 | addr = iph->daddr; |
@@ -246,7 +247,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, | |||
246 | iph->saddr = new_addr; | 247 | iph->saddr = new_addr; |
247 | 248 | ||
248 | inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, | 249 | inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, |
249 | 1); | 250 | 0); |
250 | break; | 251 | break; |
251 | } | 252 | } |
252 | default: | 253 | default: |
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 4f522143811e..7416a5c73b2a 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c | |||
@@ -134,10 +134,12 @@ next_knode: | |||
134 | #endif | 134 | #endif |
135 | 135 | ||
136 | for (i = n->sel.nkeys; i>0; i--, key++) { | 136 | for (i = n->sel.nkeys; i>0; i--, key++) { |
137 | unsigned int toff; | 137 | int toff = off + key->off + (off2 & key->offmask); |
138 | __be32 *data, _data; | 138 | __be32 *data, _data; |
139 | 139 | ||
140 | toff = off + key->off + (off2 & key->offmask); | 140 | if (skb_headroom(skb) + toff < 0) |
141 | goto out; | ||
142 | |||
141 | data = skb_header_pointer(skb, toff, 4, &_data); | 143 | data = skb_header_pointer(skb, toff, 4, &_data); |
142 | if (!data) | 144 | if (!data) |
143 | goto out; | 145 | goto out; |