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; |
