Merge branch 'upstream/android-3.10' into linaro-fixes/android-3.10
authorJohn Stultz <john.stultz@linaro.org>
Wed, 11 Jun 2014 19:24:59 +0000 (12:24 -0700)
committerJohn Stultz <john.stultz@linaro.org>
Wed, 11 Jun 2014 19:24:59 +0000 (12:24 -0700)
34 files changed:
Documentation/networking/ip-sysctl.txt
android/configs/android-base.cfg
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/keycombo.c [new file with mode: 0644]
drivers/input/keyreset.c
drivers/tty/n_tty.c
include/linux/ipv6.h
include/linux/keycombo.h [new file with mode: 0644]
include/linux/keyreset.h
include/net/addrconf.h
include/net/inet_sock.h
include/net/ip.h
include/net/ipv6.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/uapi/linux/ipv6.h
kernel/futex.c
net/core/fib_rules.c
net/ipv4/icmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/ip_output.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_ipv4.c
net/ipv6/addrconf.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ping.c
net/ipv6/route.c
net/ipv6/syncookies.c
net/ipv6/sysctl_net_ipv6.c
net/ipv6/tcp_ipv6.c

index 3458d6343e01de0e66f0d3f2e09efc61bab3b886..6e5c7c7333bdb3aa73a84a2509670f289abc958b 100644 (file)
@@ -22,6 +22,15 @@ ip_no_pmtu_disc - BOOLEAN
 min_pmtu - INTEGER
        default 552 - minimum discovered Path MTU
 
+fwmark_reflect - BOOLEAN
+       Controls the fwmark of kernel-generated IPv4 reply packets that are not
+       associated with a socket for example, TCP RSTs or ICMP echo replies).
+       If unset, these packets have a fwmark of zero. If set, they have the
+       fwmark of the packet they are replying to. Similarly affects the fwmark
+       used by internal routing lookups triggered by incoming packets, such as
+       the ones used for Path MTU Discovery.
+       Default: 0
+
 route/max_size - INTEGER
        Maximum number of routes allowed in the kernel.  Increase
        this when using large numbers of interfaces and/or routes.
@@ -468,6 +477,16 @@ tcp_fastopen - INTEGER
 
        See include/net/tcp.h and the code for more details.
 
+tcp_fwmark_accept - BOOLEAN
+       If set, incoming connections to listening sockets that do not have a
+       socket mark will set the mark of the accepting socket to the fwmark of
+       the incoming SYN packet. This will cause all packets on that connection
+       (starting from the first SYNACK) to be sent with that fwmark. The
+       listening socket's mark is unchanged. Listening sockets that already
+       have a fwmark set via setsockopt(SOL_SOCKET, SO_MARK, ...) are
+       unaffected.
+       Default: 0
+
 tcp_syn_retries - INTEGER
        Number of times initial SYNs for an active TCP connection attempt
        will be retransmitted. Should not be higher than 255. Default value
@@ -1087,6 +1106,15 @@ conf/all/forwarding - BOOLEAN
 proxy_ndp - BOOLEAN
        Do proxy ndp.
 
+fwmark_reflect - BOOLEAN
+       Controls the fwmark of kernel-generated IPv6 reply packets that are not
+       associated with a socket for example, TCP RSTs or ICMPv6 echo replies).
+       If unset, these packets have a fwmark of zero. If set, they have the
+       fwmark of the packet they are replying to. Similarly affects the fwmark
+       used by internal routing lookups triggered by incoming packets, such as
+       the ones used for Path MTU Discovery.
+       Default: 0
+
 conf/interface/*:
        Change special settings per interface.
 
index 04c7148cf637243fed7863a8e8943d85edfc73b2..5b888487ede11836dbb9850bf2f6a949985210ea 100644 (file)
@@ -5,7 +5,6 @@
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_ANDROID_INTF_ALARM_DEV=y
-CONFIG_ANDROID_LOGGER=y
 CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 CONFIG_ASHMEM=y
 CONFIG_BLK_DEV_DM=y
index 3ad49c1f0a304fbc2fe777f009e3d6eda3914295..c8c3d1568888381ddd9dadc1ff375cdd696ce8f5 100644 (file)
@@ -177,12 +177,22 @@ config INPUT_APMPOWER
 config INPUT_KEYRESET
        tristate "Reset key"
        depends on INPUT
+       select INPUT_KEYCOMBO
        ---help---
          Say Y here if you want to reboot when some keys are pressed;
 
          To compile this driver as a module, choose M here: the
          module will be called keyreset.
 
+config INPUT_KEYCOMBO
+       tristate "Key combo"
+       depends on INPUT
+       ---help---
+         Say Y here if you want to take action when some keys are pressed;
+
+         To compile this driver as a module, choose M here: the
+         module will be called keycombo.
+
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
index 191ea43d0800f8036aba0b065d5e580de4521fe0..ee4c06520bb436a12c4d80f26a0df277b63652e9 100644 (file)
@@ -26,3 +26,5 @@ obj-$(CONFIG_INPUT_MISC)      += misc/
 
 obj-$(CONFIG_INPUT_APMPOWER)   += apm-power.o
 obj-$(CONFIG_INPUT_KEYRESET)   += keyreset.o
+obj-$(CONFIG_INPUT_KEYCOMBO)   += keycombo.o
+
diff --git a/drivers/input/keycombo.c b/drivers/input/keycombo.c
new file mode 100644 (file)
index 0000000..2fba451
--- /dev/null
@@ -0,0 +1,261 @@
+/* drivers/input/keycombo.c
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/keycombo.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+struct keycombo_state {
+       struct input_handler input_handler;
+       unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
+       unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
+       unsigned long key[BITS_TO_LONGS(KEY_CNT)];
+       spinlock_t lock;
+       struct  workqueue_struct *wq;
+       int key_down_target;
+       int key_down;
+       int key_up;
+       struct delayed_work key_down_work;
+       int delay;
+       struct work_struct key_up_work;
+       void (*key_up_fn)(void *);
+       void (*key_down_fn)(void *);
+       void *priv;
+       int key_is_down;
+       struct wakeup_source combo_held_wake_source;
+       struct wakeup_source combo_up_wake_source;
+};
+
+static void do_key_down(struct work_struct *work)
+{
+       struct delayed_work *dwork = container_of(work, struct delayed_work,
+                                                                       work);
+       struct keycombo_state *state = container_of(dwork,
+                                       struct keycombo_state, key_down_work);
+       if (state->key_down_fn)
+               state->key_down_fn(state->priv);
+}
+
+static void do_key_up(struct work_struct *work)
+{
+       struct keycombo_state *state = container_of(work, struct keycombo_state,
+                                                               key_up_work);
+       if (state->key_up_fn)
+               state->key_up_fn(state->priv);
+       __pm_relax(&state->combo_up_wake_source);
+}
+
+static void keycombo_event(struct input_handle *handle, unsigned int type,
+               unsigned int code, int value)
+{
+       unsigned long flags;
+       struct keycombo_state *state = handle->private;
+
+       if (type != EV_KEY)
+               return;
+
+       if (code >= KEY_MAX)
+               return;
+
+       if (!test_bit(code, state->keybit))
+               return;
+
+       spin_lock_irqsave(&state->lock, flags);
+       if (!test_bit(code, state->key) == !value)
+               goto done;
+       __change_bit(code, state->key);
+       if (test_bit(code, state->upbit)) {
+               if (value)
+                       state->key_up++;
+               else
+                       state->key_up--;
+       } else {
+               if (value)
+                       state->key_down++;
+               else
+                       state->key_down--;
+       }
+       if (state->key_down == state->key_down_target && state->key_up == 0) {
+               __pm_stay_awake(&state->combo_held_wake_source);
+               state->key_is_down = 1;
+               if (queue_delayed_work(state->wq, &state->key_down_work,
+                                                               state->delay))
+                       pr_debug("Key down work already queued!");
+       } else if (state->key_is_down) {
+               if (!cancel_delayed_work(&state->key_down_work)) {
+                       __pm_stay_awake(&state->combo_up_wake_source);
+                       queue_work(state->wq, &state->key_up_work);
+               }
+               __pm_relax(&state->combo_held_wake_source);
+               state->key_is_down = 0;
+       }
+done:
+       spin_unlock_irqrestore(&state->lock, flags);
+}
+
+static int keycombo_connect(struct input_handler *handler,
+               struct input_dev *dev,
+               const struct input_device_id *id)
+{
+       int i;
+       int ret;
+       struct input_handle *handle;
+       struct keycombo_state *state =
+               container_of(handler, struct keycombo_state, input_handler);
+       for (i = 0; i < KEY_MAX; i++) {
+               if (test_bit(i, state->keybit) && test_bit(i, dev->keybit))
+                       break;
+       }
+       if (i == KEY_MAX)
+               return -ENODEV;
+
+       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = KEYCOMBO_NAME;
+       handle->private = state;
+
+       ret = input_register_handle(handle);
+       if (ret)
+               goto err_input_register_handle;
+
+       ret = input_open_device(handle);
+       if (ret)
+               goto err_input_open_device;
+
+       return 0;
+
+err_input_open_device:
+       input_unregister_handle(handle);
+err_input_register_handle:
+       kfree(handle);
+       return ret;
+}
+
+static void keycombo_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+static const struct input_device_id keycombo_ids[] = {
+               {
+                               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                               .evbit = { BIT_MASK(EV_KEY) },
+               },
+               { },
+};
+MODULE_DEVICE_TABLE(input, keycombo_ids);
+
+static int keycombo_probe(struct platform_device *pdev)
+{
+       int ret;
+       int key, *keyp;
+       struct keycombo_state *state;
+       struct keycombo_platform_data *pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               return -EINVAL;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       spin_lock_init(&state->lock);
+       keyp = pdata->keys_down;
+       while ((key = *keyp++)) {
+               if (key >= KEY_MAX)
+                       continue;
+               state->key_down_target++;
+               __set_bit(key, state->keybit);
+       }
+       if (pdata->keys_up) {
+               keyp = pdata->keys_up;
+               while ((key = *keyp++)) {
+                       if (key >= KEY_MAX)
+                               continue;
+                       __set_bit(key, state->keybit);
+                       __set_bit(key, state->upbit);
+               }
+       }
+
+       state->wq = alloc_ordered_workqueue("keycombo", 0);
+       if (!state->wq)
+               return -ENOMEM;
+
+       state->priv = pdata->priv;
+
+       if (pdata->key_down_fn)
+               state->key_down_fn = pdata->key_down_fn;
+       INIT_DELAYED_WORK(&state->key_down_work, do_key_down);
+
+       if (pdata->key_up_fn)
+               state->key_up_fn = pdata->key_up_fn;
+       INIT_WORK(&state->key_up_work, do_key_up);
+
+       wakeup_source_init(&state->combo_held_wake_source, "key combo");
+       wakeup_source_init(&state->combo_up_wake_source, "key combo up");
+       state->delay = msecs_to_jiffies(pdata->key_down_delay);
+
+       state->input_handler.event = keycombo_event;
+       state->input_handler.connect = keycombo_connect;
+       state->input_handler.disconnect = keycombo_disconnect;
+       state->input_handler.name = KEYCOMBO_NAME;
+       state->input_handler.id_table = keycombo_ids;
+       ret = input_register_handler(&state->input_handler);
+       if (ret) {
+               kfree(state);
+               return ret;
+       }
+       platform_set_drvdata(pdev, state);
+       return 0;
+}
+
+int keycombo_remove(struct platform_device *pdev)
+{
+       struct keycombo_state *state = platform_get_drvdata(pdev);
+       input_unregister_handler(&state->input_handler);
+       destroy_workqueue(state->wq);
+       kfree(state);
+       return 0;
+}
+
+
+struct platform_driver keycombo_driver = {
+               .driver.name = KEYCOMBO_NAME,
+               .probe = keycombo_probe,
+               .remove = keycombo_remove,
+};
+
+static int __init keycombo_init(void)
+{
+       return platform_driver_register(&keycombo_driver);
+}
+
+static void __exit keycombo_exit(void)
+{
+       return platform_driver_unregister(&keycombo_driver);
+}
+
+module_init(keycombo_init);
+module_exit(keycombo_exit);
index 36208fe0baae66ce7f6fb7aa02427de15d674122..eaaccde8221013c4faec1ef932732d463139136f 100644 (file)
@@ -1,6 +1,6 @@
 /* drivers/input/keyreset.c
  *
- * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2014 Google, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/syscalls.h>
-
+#include <linux/keycombo.h>
 
 struct keyreset_state {
-       struct input_handler input_handler;
-       unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
-       unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
-       unsigned long key[BITS_TO_LONGS(KEY_CNT)];
-       spinlock_t lock;
-       int key_down_target;
-       int key_down;
-       int key_up;
-       int restart_disabled;
+       int restart_requested;
        int (*reset_fn)(void);
+       struct platform_device *pdev_child;
 };
 
-int restart_requested;
-static void deferred_restart(struct work_struct *dummy)
+static void do_restart(void)
 {
-       restart_requested = 2;
        sys_sync();
-       restart_requested = 3;
        kernel_restart(NULL);
 }
-static DECLARE_WORK(restart_work, deferred_restart);
 
-static void keyreset_event(struct input_handle *handle, unsigned int type,
-                          unsigned int code, int value)
+static void do_reset_fn(void *priv)
 {
-       unsigned long flags;
-       struct keyreset_state *state = handle->private;
-
-       if (type != EV_KEY)
-               return;
-
-       if (code >= KEY_MAX)
-               return;
-
-       if (!test_bit(code, state->keybit))
-               return;
-
-       spin_lock_irqsave(&state->lock, flags);
-       if (!test_bit(code, state->key) == !value)
-               goto done;
-       __change_bit(code, state->key);
-       if (test_bit(code, state->upbit)) {
-               if (value) {
-                       state->restart_disabled = 1;
-                       state->key_up++;
-               } else
-                       state->key_up--;
+       struct keyreset_state *state = priv;
+       if (state->restart_requested)
+               panic("keyboard reset failed, %d", state->restart_requested);
+       if (state->reset_fn) {
+               state->restart_requested = state->reset_fn();
        } else {
-               if (value)
-                       state->key_down++;
-               else
-                       state->key_down--;
+               pr_info("keyboard reset\n");
+               do_restart();
+               state->restart_requested = 1;
        }
-       if (state->key_down == 0 && state->key_up == 0)
-               state->restart_disabled = 0;
-
-       pr_debug("reset key changed %d %d new state %d-%d-%d\n", code, value,
-                state->key_down, state->key_up, state->restart_disabled);
-
-       if (value && !state->restart_disabled &&
-           state->key_down == state->key_down_target) {
-               state->restart_disabled = 1;
-               if (restart_requested)
-                       panic("keyboard reset failed, %d", restart_requested);
-               if (state->reset_fn) {
-                       restart_requested = state->reset_fn();
-               } else {
-                       pr_info("keyboard reset\n");
-                       schedule_work(&restart_work);
-                       restart_requested = 1;
-               }
-       }
-done:
-       spin_unlock_irqrestore(&state->lock, flags);
 }
 
-static int keyreset_connect(struct input_handler *handler,
-                                         struct input_dev *dev,
-                                         const struct input_device_id *id)
-{
-       int i;
-       int ret;
-       struct input_handle *handle;
-       struct keyreset_state *state =
-               container_of(handler, struct keyreset_state, input_handler);
-
-       for (i = 0; i < KEY_MAX; i++) {
-               if (test_bit(i, state->keybit) && test_bit(i, dev->keybit))
-                       break;
-       }
-       if (i == KEY_MAX)
-               return -ENODEV;
-
-       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "keyreset";
-       handle->private = state;
-
-       ret = input_register_handle(handle);
-       if (ret)
-               goto err_input_register_handle;
-
-       ret = input_open_device(handle);
-       if (ret)
-               goto err_input_open_device;
-
-       pr_info("using input dev %s for key reset\n", dev->name);
-
-       return 0;
-
-err_input_open_device:
-       input_unregister_handle(handle);
-err_input_register_handle:
-       kfree(handle);
-       return ret;
-}
-
-static void keyreset_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-static const struct input_device_id keyreset_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(input, keyreset_ids);
-
 static int keyreset_probe(struct platform_device *pdev)
 {
-       int ret;
+       int ret = -ENOMEM;
+       struct keycombo_platform_data *pdata_child;
+       struct keyreset_platform_data *pdata = pdev->dev.platform_data;
+       int up_size = 0, down_size = 0, size;
        int key, *keyp;
        struct keyreset_state *state;
-       struct keyreset_platform_data *pdata = pdev->dev.platform_data;
 
        if (!pdata)
                return -EINVAL;
-
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
                return -ENOMEM;
 
-       spin_lock_init(&state->lock);
+       state->pdev_child = platform_device_alloc(KEYCOMBO_NAME,
+                                                       PLATFORM_DEVID_AUTO);
+       if (!state->pdev_child)
+               return -ENOMEM;
+       state->pdev_child->dev.parent = &pdev->dev;
+
        keyp = pdata->keys_down;
        while ((key = *keyp++)) {
                if (key >= KEY_MAX)
                        continue;
-               state->key_down_target++;
-               __set_bit(key, state->keybit);
+               down_size++;
        }
        if (pdata->keys_up) {
                keyp = pdata->keys_up;
                while ((key = *keyp++)) {
                        if (key >= KEY_MAX)
                                continue;
-                       __set_bit(key, state->keybit);
-                       __set_bit(key, state->upbit);
+                       up_size++;
                }
        }
-
-       if (pdata->reset_fn)
-               state->reset_fn = pdata->reset_fn;
-
-       state->input_handler.event = keyreset_event;
-       state->input_handler.connect = keyreset_connect;
-       state->input_handler.disconnect = keyreset_disconnect;
-       state->input_handler.name = KEYRESET_NAME;
-       state->input_handler.id_table = keyreset_ids;
-       ret = input_register_handler(&state->input_handler);
-       if (ret) {
-               kfree(state);
-               return ret;
+       size = sizeof(struct keycombo_platform_data)
+                       + sizeof(int) * (down_size + 1);
+       pdata_child = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!pdata_child)
+               goto error;
+       memcpy(pdata_child->keys_down, pdata->keys_down,
+                                               sizeof(int) * down_size);
+       if (up_size > 0) {
+               pdata_child->keys_up = devm_kzalloc(&pdev->dev, up_size + 1,
+                                                               GFP_KERNEL);
+               if (!pdata_child->keys_up)
+                       goto error;
+               memcpy(pdata_child->keys_up, pdata->keys_up,
+                                                       sizeof(int) * up_size);
+               if (!pdata_child->keys_up)
+                       goto error;
        }
+       state->reset_fn = pdata->reset_fn;
+       pdata_child->key_down_fn = do_reset_fn;
+       pdata_child->priv = state;
+       pdata_child->key_down_delay = pdata->key_down_delay;
+       ret = platform_device_add_data(state->pdev_child, pdata_child, size);
+       if (ret)
+               goto error;
        platform_set_drvdata(pdev, state);
-       return 0;
+       return platform_device_add(state->pdev_child);
+error:
+       platform_device_put(state->pdev_child);
+       return ret;
 }
 
 int keyreset_remove(struct platform_device *pdev)
 {
        struct keyreset_state *state = platform_get_drvdata(pdev);
-       input_unregister_handler(&state->input_handler);
-       kfree(state);
+       platform_device_put(state->pdev_child);
        return 0;
 }
 
index 6c7fe90ad72d48d2834536331e6826ee2719f94f..6cfe4019abc63b3f3321df606e57bdd38ed6be72 100644 (file)
@@ -2066,8 +2066,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
                        if (tty->ops->flush_chars)
                                tty->ops->flush_chars(tty);
                } else {
+                       struct n_tty_data *ldata = tty->disc_data;
+
                        while (nr > 0) {
+                               mutex_lock(&ldata->output_lock);
                                c = tty->ops->write(tty, b, nr);
+                               mutex_unlock(&ldata->output_lock);
                                if (c < 0) {
                                        retval = c;
                                        goto break_out;
index 850e95bc766c8504d4fbc2c592c1327ef5994431..867833ba6bd166dbfcc4e1259b6dfbcdd00d0650 100644 (file)
@@ -36,6 +36,7 @@ struct ipv6_devconf {
        __s32           accept_ra_rt_info_max_plen;
 #endif
 #endif
+       __s32           accept_ra_rt_table;
        __s32           proxy_ndp;
        __s32           accept_source_route;
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
diff --git a/include/linux/keycombo.h b/include/linux/keycombo.h
new file mode 100644 (file)
index 0000000..c6db262
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * include/linux/keycombo.h - platform data structure for keycombo driver
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_KEYCOMBO_H
+#define _LINUX_KEYCOMBO_H
+
+#define KEYCOMBO_NAME "keycombo"
+
+/*
+ * if key_down_fn and key_up_fn are both present, you are guaranteed that
+ * key_down_fn will return before key_up_fn is called, and that key_up_fn
+ * is called iff key_down_fn is called.
+ */
+struct keycombo_platform_data {
+       void (*key_down_fn)(void *);
+       void (*key_up_fn)(void *);
+       void *priv;
+       int key_down_delay; /* Time in ms */
+       int *keys_up;
+       int keys_down[]; /* 0 terminated */
+};
+
+#endif /* _LINUX_KEYCOMBO_H */
index a2ac49e5b684c773d119ab178e3d498043ee602d..2e34afab65e4ae187b12897fce1dd68b64955f87 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * include/linux/keyreset.h - platform data structure for resetkeys driver
  *
- * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2014 Google, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -21,6 +21,7 @@
 
 struct keyreset_platform_data {
        int (*reset_fn)(void);
+       int key_down_delay;
        int *keys_up;
        int keys_down[]; /* 0 terminated */
 };
index 21f702704f2444272e1554c87112594d40acd421..96a8afe33c52d946d64d3f4b6e82a4099f1ad993 100644 (file)
@@ -183,6 +183,8 @@ static inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset)
 extern void addrconf_prefix_rcv(struct net_device *dev,
                                u8 *opt, int len, bool sllao);
 
+u32 addrconf_rt_table(const struct net_device *dev, u32 default_table);
+
 /*
  *     anycast prototypes (anycast.c)
  */
index 7235ae73a1e8d07a905d6803017d341d951e8f56..9528e10fa0b491f6b65c00e4b9ca88483b73e8b2 100644 (file)
@@ -88,6 +88,7 @@ struct inet_request_sock {
                                acked      : 1,
                                no_srccheck: 1;
        kmemcheck_bitfield_end(flags);
+       u32                     ir_mark;
        struct ip_options_rcu   *opt;
 };
 
@@ -96,6 +97,14 @@ static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk)
        return (struct inet_request_sock *)sk;
 }
 
+static inline u32 inet_request_mark(struct sock *sk, struct sk_buff *skb)
+{
+       if (!sk->sk_mark && sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept)
+               return skb->mark;
+
+       return sk->sk_mark;
+}
+
 struct inet_cork {
        unsigned int            flags;
        __be32                  addr;
index a68f838a132c522df397b9398f8f2d64646008c0..509b88079270b21f0e4729fb36eb028ebfaf7402 100644 (file)
@@ -225,6 +225,9 @@ extern void ipfrag_init(void);
 
 extern void ip_static_sysctl_init(void);
 
+#define IP4_REPLY_MARK(net, mark) \
+       ((net)->ipv4.sysctl_fwmark_reflect ? (mark) : 0)
+
 static inline bool ip_is_fragment(const struct iphdr *iph)
 {
        return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0;
index ab47582f6c0b46fe808e9fc53a104a23de9196b1..cc344ca9d0ae2762d158ef6a87b3147df4cb7a87 100644 (file)
@@ -111,6 +111,9 @@ struct frag_hdr {
 
 #define        IP6_MF  0x0001
 
+#define IP6_REPLY_MARK(net, mark) \
+       ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0)
+
 #include <net/sock.h>
 
 /* sysctls */
index 2ba9de89e8ec778990e8b2ff5183fd3e97eee1aa..0dd6f0b3eadb96119658697e949e50334dcd9434 100644 (file)
@@ -64,6 +64,9 @@ struct netns_ipv4 {
 
        int sysctl_tcp_ecn;
 
+       int sysctl_fwmark_reflect;
+       int sysctl_tcp_fwmark_accept;
+
        kgid_t sysctl_ping_group_range[2];
        long sysctl_tcp_mem[3];
 
index 005e2c2e39a9022bad13f4205343263f1821cb22..4b9f99e3a91c9cfc02f1f48d71ef30f2dec30880 100644 (file)
@@ -28,6 +28,7 @@ struct netns_sysctl_ipv6 {
        int ip6_rt_mtu_expires;
        int ip6_rt_min_advmss;
        int icmpv6_time;
+       int fwmark_reflect;
 };
 
 struct netns_ipv6 {
index 4bda4cf5b0f56d84651497df86bd9fa09909fa85..4214fac1bf4fbeea0c702c440f39aaa6cad94291 100644 (file)
@@ -160,6 +160,7 @@ enum {
        DEVCONF_ACCEPT_DAD,
        DEVCONF_FORCE_TLLAO,
        DEVCONF_NDISC_NOTIFY,
+       DEVCONF_ACCEPT_RA_RT_TABLE,
        DEVCONF_MAX
 };
 
index d710fae8abbe933b97267b69ff2e27864d1291a4..590483b726eb0cc81bc383fabd15076e1618ede0 100644 (file)
@@ -590,6 +590,55 @@ void exit_pi_state_list(struct task_struct *curr)
        raw_spin_unlock_irq(&curr->pi_lock);
 }
 
+/*
+ * We need to check the following states:
+ *
+ *      Waiter | pi_state | pi->owner | uTID      | uODIED | ?
+ *
+ * [1]  NULL   | ---      | ---       | 0         | 0/1    | Valid
+ * [2]  NULL   | ---      | ---       | >0        | 0/1    | Valid
+ *
+ * [3]  Found  | NULL     | --        | Any       | 0/1    | Invalid
+ *
+ * [4]  Found  | Found    | NULL      | 0         | 1      | Valid
+ * [5]  Found  | Found    | NULL      | >0        | 1      | Invalid
+ *
+ * [6]  Found  | Found    | task      | 0         | 1      | Valid
+ *
+ * [7]  Found  | Found    | NULL      | Any       | 0      | Invalid
+ *
+ * [8]  Found  | Found    | task      | ==taskTID | 0/1    | Valid
+ * [9]  Found  | Found    | task      | 0         | 0      | Invalid
+ * [10] Found  | Found    | task      | !=taskTID | 0/1    | Invalid
+ *
+ * [1] Indicates that the kernel can acquire the futex atomically. We
+ *     came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
+ *
+ * [2] Valid, if TID does not belong to a kernel thread. If no matching
+ *      thread is found then it indicates that the owner TID has died.
+ *
+ * [3] Invalid. The waiter is queued on a non PI futex
+ *
+ * [4] Valid state after exit_robust_list(), which sets the user space
+ *     value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
+ *
+ * [5] The user space value got manipulated between exit_robust_list()
+ *     and exit_pi_state_list()
+ *
+ * [6] Valid state after exit_pi_state_list() which sets the new owner in
+ *     the pi_state but cannot access the user space value.
+ *
+ * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set.
+ *
+ * [8] Owner and user space value match
+ *
+ * [9] There is no transient state which sets the user space TID to 0
+ *     except exit_robust_list(), but this is indicated by the
+ *     FUTEX_OWNER_DIED bit. See [4]
+ *
+ * [10] There is no transient state which leaves owner and user space
+ *     TID out of sync.
+ */
 static int
 lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
                union futex_key *key, struct futex_pi_state **ps)
@@ -605,12 +654,13 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
        plist_for_each_entry_safe(this, next, head, list) {
                if (match_futex(&this->key, key)) {
                        /*
-                        * Another waiter already exists - bump up
-                        * the refcount and return its pi_state:
+                        * Sanity check the waiter before increasing
+                        * the refcount and attaching to it.
                         */
                        pi_state = this->pi_state;
                        /*
-                        * Userspace might have messed up non-PI and PI futexes
+                        * Userspace might have messed up non-PI and
+                        * PI futexes [3]
                         */
                        if (unlikely(!pi_state))
                                return -EINVAL;
@@ -618,34 +668,70 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
                        WARN_ON(!atomic_read(&pi_state->refcount));
 
                        /*
-                        * When pi_state->owner is NULL then the owner died
-                        * and another waiter is on the fly. pi_state->owner
-                        * is fixed up by the task which acquires
-                        * pi_state->rt_mutex.
-                        *
-                        * We do not check for pid == 0 which can happen when
-                        * the owner died and robust_list_exit() cleared the
-                        * TID.
+                        * Handle the owner died case:
                         */
-                       if (pid && pi_state->owner) {
+                       if (uval & FUTEX_OWNER_DIED) {
+                               /*
+                                * exit_pi_state_list sets owner to NULL and
+                                * wakes the topmost waiter. The task which
+                                * acquires the pi_state->rt_mutex will fixup
+                                * owner.
+                                */
+                               if (!pi_state->owner) {
+                                       /*
+                                        * No pi state owner, but the user
+                                        * space TID is not 0. Inconsistent
+                                        * state. [5]
+                                        */
+                                       if (pid)
+                                               return -EINVAL;
+                                       /*
+                                        * Take a ref on the state and
+                                        * return. [4]
+                                        */
+                                       goto out_state;
+                               }
+
                                /*
-                                * Bail out if user space manipulated the
-                                * futex value.
+                                * If TID is 0, then either the dying owner
+                                * has not yet executed exit_pi_state_list()
+                                * or some waiter acquired the rtmutex in the
+                                * pi state, but did not yet fixup the TID in
+                                * user space.
+                                *
+                                * Take a ref on the state and return. [6]
                                 */
-                               if (pid != task_pid_vnr(pi_state->owner))
+                               if (!pid)
+                                       goto out_state;
+                       } else {
+                               /*
+                                * If the owner died bit is not set,
+                                * then the pi_state must have an
+                                * owner. [7]
+                                */
+                               if (!pi_state->owner)
                                        return -EINVAL;
                        }
 
+                       /*
+                        * Bail out if user space manipulated the
+                        * futex value. If pi state exists then the
+                        * owner TID must be the same as the user
+                        * space TID. [9/10]
+                        */
+                       if (pid != task_pid_vnr(pi_state->owner))
+                               return -EINVAL;
+
+               out_state:
                        atomic_inc(&pi_state->refcount);
                        *ps = pi_state;
-
                        return 0;
                }
        }
 
        /*
         * We are the first waiter - try to look up the real owner and attach
-        * the new pi_state to it, but bail out when TID = 0
+        * the new pi_state to it, but bail out when TID = 0 [1]
         */
        if (!pid)
                return -ESRCH;
@@ -673,6 +759,9 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
                return ret;
        }
 
+       /*
+        * No existing pi state. First waiter. [2]
+        */
        pi_state = alloc_pi_state();
 
        /*
@@ -744,10 +833,18 @@ retry:
                return -EDEADLK;
 
        /*
-        * Surprise - we got the lock. Just return to userspace:
+        * Surprise - we got the lock, but we do not trust user space at all.
         */
-       if (unlikely(!curval))
-               return 1;
+       if (unlikely(!curval)) {
+               /*
+                * We verify whether there is kernel state for this
+                * futex. If not, we can safely assume, that the 0 ->
+                * TID transition is correct. If state exists, we do
+                * not bother to fixup the user space state as it was
+                * corrupted already.
+                */
+               return futex_top_waiter(hb, key) ? -EINVAL : 1;
+       }
 
        uval = curval;
 
@@ -877,6 +974,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
        struct task_struct *new_owner;
        struct futex_pi_state *pi_state = this->pi_state;
        u32 uninitialized_var(curval), newval;
+       int ret = 0;
 
        if (!pi_state)
                return -EINVAL;
@@ -900,23 +998,19 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
                new_owner = this->task;
 
        /*
-        * We pass it to the next owner. (The WAITERS bit is always
-        * kept enabled while there is PI state around. We must also
-        * preserve the owner died bit.)
+        * We pass it to the next owner. The WAITERS bit is always
+        * kept enabled while there is PI state around. We cleanup the
+        * owner died bit, because we are the owner.
         */
-       if (!(uval & FUTEX_OWNER_DIED)) {
-               int ret = 0;
-
-               newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
+       newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
 
-               if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
-                       ret = -EFAULT;
-               else if (curval != uval)
-                       ret = -EINVAL;
-               if (ret) {
-                       raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
-                       return ret;
-               }
+       if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
+               ret = -EFAULT;
+       else if (curval != uval)
+               ret = -EINVAL;
+       if (ret) {
+               raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
+               return ret;
        }
 
        raw_spin_lock_irq(&pi_state->owner->pi_lock);
@@ -1273,6 +1367,13 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
        u32 curval2;
 
        if (requeue_pi) {
+               /*
+                * Requeue PI only works on two distinct uaddrs. This
+                * check is only valid for private futexes. See below.
+                */
+               if (uaddr1 == uaddr2)
+                       return -EINVAL;
+
                /*
                 * requeue_pi requires a pi_state, try to allocate it now
                 * without any locks in case it fails.
@@ -1311,6 +1412,15 @@ retry:
        if (unlikely(ret != 0))
                goto out_put_key1;
 
+       /*
+        * The check above which compares uaddrs is not sufficient for
+        * shared futexes. We need to compare the keys:
+        */
+       if (requeue_pi && match_futex(&key1, &key2)) {
+               ret = -EINVAL;
+               goto out_put_keys;
+       }
+
        hb1 = hash_futex(&key1);
        hb2 = hash_futex(&key2);
 
@@ -2135,9 +2245,10 @@ retry:
        /*
         * To avoid races, try to do the TID -> 0 atomic transition
         * again. If it succeeds then we can return without waking
-        * anyone else up:
+        * anyone else up. We only try this if neither the waiters nor
+        * the owner died bit are set.
         */
-       if (!(uval & FUTEX_OWNER_DIED) &&
+       if (!(uval & ~FUTEX_TID_MASK) &&
            cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
                goto pi_faulted;
        /*
@@ -2169,11 +2280,9 @@ retry:
        /*
         * No waiters - kernel unlocks the futex:
         */
-       if (!(uval & FUTEX_OWNER_DIED)) {
-               ret = unlock_futex_pi(uaddr, uval);
-               if (ret == -EFAULT)
-                       goto pi_faulted;
-       }
+       ret = unlock_futex_pi(uaddr, uval);
+       if (ret == -EFAULT)
+               goto pi_faulted;
 
 out_unlock:
        spin_unlock(&hb->lock);
@@ -2332,6 +2441,15 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
        if (ret)
                goto out_key2;
 
+       /*
+        * The check above which compares uaddrs is not sufficient for
+        * shared futexes. We need to compare the keys:
+        */
+       if (match_futex(&q.key, &key2)) {
+               ret = -EINVAL;
+               goto out_put_keys;
+       }
+
        /* Queue the futex_q, drop the hb lock, wait for wakeup. */
        futex_wait_queue_me(hb, &q, to);
 
index d5a9f8ead0d864305110f2ca6f1dc70fca5b84cd..0e9131195eb09708c786c00a11ce9ff27bd4e7bf 100644 (file)
@@ -445,7 +445,8 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh)
                if (frh->action && (frh->action != rule->action))
                        continue;
 
-               if (frh->table && (frh_get_table(frh, tb) != rule->table))
+               if (frh_get_table(frh, tb) &&
+                   (frh_get_table(frh, tb) != rule->table))
                        continue;
 
                if (tb[FRA_PRIORITY] &&
index 562efd91f457f324335ec6ee75ff469d28266d72..cc38f44306ed29bca916f2428332bebee6573a8e 100644 (file)
@@ -337,6 +337,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        struct sock *sk;
        struct inet_sock *inet;
        __be32 daddr, saddr;
+       u32 mark = IP4_REPLY_MARK(net, skb->mark);
 
        if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
                return;
@@ -349,6 +350,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        icmp_param->data.icmph.checksum = 0;
 
        inet->tos = ip_hdr(skb)->tos;
+       sk->sk_mark = mark;
        daddr = ipc.addr = ip_hdr(skb)->saddr;
        saddr = fib_compute_spec_dst(skb);
        ipc.opt = NULL;
@@ -361,6 +363,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
        memset(&fl4, 0, sizeof(fl4));
        fl4.daddr = daddr;
        fl4.saddr = saddr;
+       fl4.flowi4_mark = mark;
        fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
        fl4.flowi4_proto = IPPROTO_ICMP;
        security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
@@ -379,7 +382,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
                                        struct flowi4 *fl4,
                                        struct sk_buff *skb_in,
                                        const struct iphdr *iph,
-                                       __be32 saddr, u8 tos,
+                                       __be32 saddr, u8 tos, u32 mark,
                                        int type, int code,
                                        struct icmp_bxm *param)
 {
@@ -391,6 +394,7 @@ static struct rtable *icmp_route_lookup(struct net *net,
        fl4->daddr = (param->replyopts.opt.opt.srr ?
                      param->replyopts.opt.opt.faddr : iph->saddr);
        fl4->saddr = saddr;
+       fl4->flowi4_mark = mark;
        fl4->flowi4_tos = RT_TOS(tos);
        fl4->flowi4_proto = IPPROTO_ICMP;
        fl4->fl4_icmp_type = type;
@@ -488,6 +492,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
        struct flowi4 fl4;
        __be32 saddr;
        u8  tos;
+       u32 mark;
        struct net *net;
        struct sock *sk;
 
@@ -584,6 +589,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
        tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
                                           IPTOS_PREC_INTERNETCONTROL) :
                                          iph->tos;
+       mark = IP4_REPLY_MARK(net, skb_in->mark);
 
        if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in))
                goto out_unlock;
@@ -600,11 +606,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
        icmp_param.skb    = skb_in;
        icmp_param.offset = skb_network_offset(skb_in);
        inet_sk(sk)->tos = tos;
+       sk->sk_mark = mark;
        ipc.addr = iph->saddr;
        ipc.opt = &icmp_param.replyopts.opt;
        ipc.tx_flags = 0;
 
-       rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos,
+       rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark,
                               type, code, &icmp_param);
        if (IS_ERR(rt))
                goto out_unlock;
index 6acb541c90910204f02449e7500138362da6998a..442087d371f69e637a85682378381fbd0927e812 100644 (file)
@@ -417,7 +417,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
        struct net *net = sock_net(sk);
        int flags = inet_sk_flowi_flags(sk);
 
-       flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
+       flowi4_init_output(fl4, sk->sk_bound_dev_if, ireq->ir_mark,
                           RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
                           sk->sk_protocol,
                           flags,
@@ -454,7 +454,7 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
 
        rcu_read_lock();
        opt = rcu_dereference(newinet->inet_opt);
-       flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
+       flowi4_init_output(fl4, sk->sk_bound_dev_if, inet_rsk(req)->ir_mark,
                           RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
                           sk->sk_protocol, inet_sk_flowi_flags(sk),
                           (opt && opt->opt.srr) ? opt->opt.faddr : ireq->rmt_addr,
@@ -688,6 +688,8 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
                inet_sk(newsk)->inet_sport = inet_rsk(req)->loc_port;
                newsk->sk_write_space = sk_stream_write_space;
 
+               newsk->sk_mark = inet_rsk(req)->ir_mark;
+
                newicsk->icsk_retransmits = 0;
                newicsk->icsk_backoff     = 0;
                newicsk->icsk_probes_out  = 0;
index 4bcabf3ab4cad3bdc43f5b9ed33eba9c1357557d..c2ee385cecfbdf68c16b4c5987614a54f0169407 100644 (file)
@@ -1497,7 +1497,8 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
                        daddr = replyopts.opt.opt.faddr;
        }
 
-       flowi4_init_output(&fl4, arg->bound_dev_if, 0,
+       flowi4_init_output(&fl4, arg->bound_dev_if,
+                          IP4_REPLY_MARK(net, skb->mark),
                           RT_TOS(arg->tos),
                           RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol,
                           ip_reply_arg_flowi_flags(arg),
index d35bbf0cf4045d04f67d30e31f15c5271058dd5a..c04359196ebcbf16f8c979db3840f19e8344258d 100644 (file)
@@ -956,6 +956,9 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,
        struct flowi4 fl4;
        struct rtable *rt;
 
+       if (!mark)
+               mark = IP4_REPLY_MARK(net, skb->mark);
+
        __build_flow_key(&fl4, NULL, iph, oif,
                         RT_TOS(iph->tos), protocol, mark, flow_flags);
        rt = __ip_route_output_key(net, &fl4);
@@ -973,6 +976,10 @@ static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)
        struct rtable *rt;
 
        __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0);
+
+       if (!fl4.flowi4_mark)
+               fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark);
+
        rt = __ip_route_output_key(sock_net(sk), &fl4);
        if (!IS_ERR(rt)) {
                __ip_rt_update_pmtu(rt, &fl4, mtu);
index b05c96e7af8b810a62bb07d95436eea07c651008..5abb45e281bea0ffdcfd14d9e017742d7b19c71a 100644 (file)
@@ -312,6 +312,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
        ireq->rmt_port          = th->source;
        ireq->loc_addr          = ip_hdr(skb)->daddr;
        ireq->rmt_addr          = ip_hdr(skb)->saddr;
+       ireq->ir_mark           = inet_request_mark(sk, skb);
        ireq->ecn_ok            = ecn_ok;
        ireq->snd_wscale        = tcp_opt.snd_wscale;
        ireq->sack_ok           = tcp_opt.sack_ok;
@@ -348,7 +349,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
         * hasn't changed since we received the original syn, but I see
         * no easy way to do this.
         */
-       flowi4_init_output(&fl4, sk->sk_bound_dev_if, sk->sk_mark,
+       flowi4_init_output(&fl4, sk->sk_bound_dev_if, ireq->ir_mark,
                           RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, IPPROTO_TCP,
                           inet_sk_flowi_flags(sk),
                           (opt && opt->srr) ? opt->faddr : ireq->rmt_addr,
index f9bb5d7488e0d3d8599efecb5db1b9386cbb25f9..cc5fa7da12e55ac83bcef34388434f65364ab993 100644 (file)
@@ -859,6 +859,20 @@ static struct ctl_table ipv4_net_table[] = {
                .mode           = 0644,
                .proc_handler   = ipv4_tcp_mem,
        },
+       {
+               .procname       = "fwmark_reflect",
+               .data           = &init_net.ipv4.sysctl_fwmark_reflect,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "tcp_fwmark_accept",
+               .data           = &init_net.ipv4.sysctl_tcp_fwmark_accept,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        { }
 };
 
index 7999fc55c83ba74abeffbd1a9d53bec25985e163..40ec14507f731156464ee6d5b18dfe9c6a48d86a 100644 (file)
@@ -1527,6 +1527,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        ireq->rmt_addr = saddr;
        ireq->no_srccheck = inet_sk(sk)->transparent;
        ireq->opt = tcp_v4_save_options(skb);
+       ireq->ir_mark = inet_request_mark(sk, skb);
 
        if (security_inet_conn_request(sk, skb, req))
                goto drop_and_free;
index 4ab4c38958c6857afd7cfe998fc8866a0da00382..cec8cb4d292db398f3d7cdd8d420f0cb3333be37 100644 (file)
@@ -198,6 +198,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .accept_ra_rt_info_max_plen = 0,
 #endif
 #endif
+       .accept_ra_rt_table     = 0,
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
        .disable_ipv6           = 0,
@@ -232,6 +233,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .accept_ra_rt_info_max_plen = 0,
 #endif
 #endif
+       .accept_ra_rt_table     = 0,
        .proxy_ndp              = 0,
        .accept_source_route    = 0,    /* we do not accept RH0 by default. */
        .disable_ipv6           = 0,
@@ -1910,6 +1912,31 @@ static void  __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmp
 }
 #endif
 
+u32 addrconf_rt_table(const struct net_device *dev, u32 default_table) {
+       /* Determines into what table to put autoconf PIO/RIO/default routes
+        * learned on this device.
+        *
+        * - If 0, use the same table for every device. This puts routes into
+        *   one of RT_TABLE_{PREFIX,INFO,DFLT} depending on the type of route
+        *   (but note that these three are currently all equal to
+        *   RT6_TABLE_MAIN).
+        * - If > 0, use the specified table.
+        * - If < 0, put routes into table dev->ifindex + (-rt_table).
+        */
+       struct inet6_dev *idev = in6_dev_get(dev);
+       u32 table;
+       int sysctl = idev->cnf.accept_ra_rt_table;
+       if (sysctl == 0) {
+               table = default_table;
+       } else if (sysctl > 0) {
+               table = (u32) sysctl;
+       } else {
+               table = (unsigned) dev->ifindex + (-sysctl);
+       }
+       in6_dev_put(idev);
+       return table;
+}
+
 /*
  *     Add prefix route.
  */
@@ -1919,7 +1946,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
                      unsigned long expires, u32 flags)
 {
        struct fib6_config cfg = {
-               .fc_table = RT6_TABLE_PREFIX,
+               .fc_table = addrconf_rt_table(dev, RT6_TABLE_PREFIX),
                .fc_metric = IP6_RT_PRIO_ADDRCONF,
                .fc_ifindex = dev->ifindex,
                .fc_expires = expires,
@@ -1953,7 +1980,8 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
        struct rt6_info *rt = NULL;
        struct fib6_table *table;
 
-       table = fib6_get_table(dev_net(dev), RT6_TABLE_PREFIX);
+       table = fib6_get_table(dev_net(dev),
+                              addrconf_rt_table(dev, RT6_TABLE_PREFIX));
        if (table == NULL)
                return NULL;
 
@@ -4159,6 +4187,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
 #endif
 #endif
+       array[DEVCONF_ACCEPT_RA_RT_TABLE] = cnf->accept_ra_rt_table;
        array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
        array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -4867,6 +4896,13 @@ static struct addrconf_sysctl_table
                },
 #endif
 #endif
+               {
+                       .procname       = "accept_ra_rt_table",
+                       .data           = &ipv6_devconf.accept_ra_rt_table,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
+               },
                {
                        .procname       = "proxy_ndp",
                        .data           = &ipv6_devconf.proxy_ndp,
index 1d2902e617866eee6553ff1197ee464d745886ef..28da4003e842a297ae175d4564b66839b969fb20 100644 (file)
@@ -397,6 +397,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        int len;
        int hlimit;
        int err = 0;
+       u32 mark = IP6_REPLY_MARK(net, skb->mark);
 
        if ((u8 *)hdr < skb->head ||
            (skb->network_header + sizeof(*hdr)) > skb->tail)
@@ -462,6 +463,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        fl6.daddr = hdr->saddr;
        if (saddr)
                fl6.saddr = *saddr;
+       fl6.flowi6_mark = mark;
        fl6.flowi6_oif = iif;
        fl6.fl6_icmp_type = type;
        fl6.fl6_icmp_code = code;
@@ -470,6 +472,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        sk = icmpv6_xmit_lock(net);
        if (sk == NULL)
                return;
+       sk->sk_mark = mark;
        np = inet6_sk(sk);
 
        if (!icmpv6_xrlim_allow(sk, type, &fl6))
@@ -551,6 +554,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
        struct dst_entry *dst;
        int err = 0;
        int hlimit;
+       u32 mark = IP6_REPLY_MARK(net, skb->mark);
 
        saddr = &ipv6_hdr(skb)->daddr;
 
@@ -567,11 +571,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
                fl6.saddr = *saddr;
        fl6.flowi6_oif = skb->dev->ifindex;
        fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY;
+       fl6.flowi6_mark = mark;
        security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
 
        sk = icmpv6_xmit_lock(net);
        if (sk == NULL)
                return;
+       sk->sk_mark = mark;
        np = inet6_sk(sk);
 
        if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
index e4311cbc8b4ecbf70ea1fb2e2f2415342be382cc..f1493138d21e237de7fdeb150b3053962690f71a 100644 (file)
@@ -81,7 +81,7 @@ struct dst_entry *inet6_csk_route_req(struct sock *sk,
        final_p = fl6_update_dst(fl6, np->opt, &final);
        fl6->saddr = treq->loc_addr;
        fl6->flowi6_oif = treq->iif;
-       fl6->flowi6_mark = sk->sk_mark;
+       fl6->flowi6_mark = inet_rsk(req)->ir_mark;
        fl6->fl6_dport = inet_rsk(req)->rmt_port;
        fl6->fl6_sport = inet_rsk(req)->loc_port;
        security_req_classify_flow(req, flowi6_to_flowi(fl6));
index e2cc17cd1cfd0214aae137d11fe2e7f7ba00f348..8d1c2064056365e64775f2a8557cd00669293a99 100644 (file)
@@ -158,6 +158,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        fl6.flowi6_proto = IPPROTO_ICMPV6;
        fl6.saddr = np->saddr;
        fl6.daddr = *daddr;
+       fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_icmp_type = user_icmph.icmp6_type;
        fl6.fl6_icmp_code = user_icmph.icmp6_code;
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
index ad0aa6b0b86ae02f80b6b2184588605a3d5d7a6c..8ecf44af7c2ef273be3f426cb652ad493e692f1d 100644 (file)
@@ -85,13 +85,12 @@ static void         rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
                                        struct sk_buff *skb);
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_add_route_info(struct net *net,
+static struct rt6_info *rt6_add_route_info(struct net_device *dev,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex,
-                                          unsigned int pref);
-static struct rt6_info *rt6_get_route_info(struct net *net,
+                                          const struct in6_addr *gwaddr, unsigned int pref);
+static struct rt6_info *rt6_get_route_info(struct net_device *dev,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex);
+                                          const struct in6_addr *gwaddr);
 #endif
 
 static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
@@ -643,7 +642,6 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
 int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
                  const struct in6_addr *gwaddr)
 {
-       struct net *net = dev_net(dev);
        struct route_info *rinfo = (struct route_info *) opt;
        struct in6_addr prefix_buf, *prefix;
        unsigned int pref;
@@ -685,8 +683,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
                prefix = &prefix_buf;
        }
 
-       rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
-                               dev->ifindex);
+       rt = rt6_get_route_info(dev, prefix, rinfo->prefix_len, gwaddr);
 
        if (rt && !lifetime) {
                ip6_del_rt(rt);
@@ -694,8 +691,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
        }
 
        if (!rt && lifetime)
-               rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
-                                       pref);
+               rt = rt6_add_route_info(dev, prefix, rinfo->prefix_len, gwaddr, pref);
        else if (rt)
                rt->rt6i_flags = RTF_ROUTEINFO |
                                 (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
@@ -1111,7 +1107,7 @@ void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
 
        memset(&fl6, 0, sizeof(fl6));
        fl6.flowi6_oif = oif;
-       fl6.flowi6_mark = mark;
+       fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark);
        fl6.flowi6_flags = 0;
        fl6.daddr = iph->daddr;
        fl6.saddr = iph->saddr;
@@ -1796,15 +1792,16 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
 }
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_get_route_info(struct net *net,
+static struct rt6_info *rt6_get_route_info(struct net_device *dev,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex)
+                                          const struct in6_addr *gwaddr)
 {
        struct fib6_node *fn;
        struct rt6_info *rt = NULL;
        struct fib6_table *table;
 
-       table = fib6_get_table(net, RT6_TABLE_INFO);
+       table = fib6_get_table(dev_net(dev),
+                              addrconf_rt_table(dev, RT6_TABLE_INFO));
        if (!table)
                return NULL;
 
@@ -1814,7 +1811,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net,
                goto out;
 
        for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) {
-               if (rt->dst.dev->ifindex != ifindex)
+               if (rt->dst.dev->ifindex != dev->ifindex)
                        continue;
                if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY))
                        continue;
@@ -1828,21 +1825,20 @@ out:
        return rt;
 }
 
-static struct rt6_info *rt6_add_route_info(struct net *net,
+static struct rt6_info *rt6_add_route_info(struct net_device *dev,
                                           const struct in6_addr *prefix, int prefixlen,
-                                          const struct in6_addr *gwaddr, int ifindex,
-                                          unsigned int pref)
+                                          const struct in6_addr *gwaddr, unsigned int pref)
 {
        struct fib6_config cfg = {
-               .fc_table       = RT6_TABLE_INFO,
+               .fc_table       = addrconf_rt_table(dev, RT6_TABLE_INFO),
                .fc_metric      = IP6_RT_PRIO_USER,
-               .fc_ifindex     = ifindex,
+               .fc_ifindex     = dev->ifindex,
                .fc_dst_len     = prefixlen,
                .fc_flags       = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
                                  RTF_UP | RTF_PREF(pref),
                .fc_nlinfo.portid = 0,
                .fc_nlinfo.nlh = NULL,
-               .fc_nlinfo.nl_net = net,
+               .fc_nlinfo.nl_net = dev_net(dev),
        };
 
        cfg.fc_dst = *prefix;
@@ -1854,7 +1850,7 @@ static struct rt6_info *rt6_add_route_info(struct net *net,
 
        ip6_route_add(&cfg);
 
-       return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
+       return rt6_get_route_info(dev, prefix, prefixlen, gwaddr);
 }
 #endif
 
@@ -1863,7 +1859,8 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev
        struct rt6_info *rt;
        struct fib6_table *table;
 
-       table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
+       table = fib6_get_table(dev_net(dev),
+                              addrconf_rt_table(dev, RT6_TABLE_MAIN));
        if (!table)
                return NULL;
 
@@ -1885,7 +1882,7 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
                                     unsigned int pref)
 {
        struct fib6_config cfg = {
-               .fc_table       = RT6_TABLE_DFLT,
+               .fc_table       = addrconf_rt_table(dev, RT6_TABLE_DFLT),
                .fc_metric      = IP6_RT_PRIO_USER,
                .fc_ifindex     = dev->ifindex,
                .fc_flags       = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
@@ -1902,28 +1899,17 @@ struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr,
        return rt6_get_dflt_router(gwaddr, dev);
 }
 
-void rt6_purge_dflt_routers(struct net *net)
-{
-       struct rt6_info *rt;
-       struct fib6_table *table;
 
-       /* NOTE: Keep consistent with rt6_get_dflt_router */
-       table = fib6_get_table(net, RT6_TABLE_DFLT);
-       if (!table)
-               return;
+int rt6_addrconf_purge(struct rt6_info *rt, void *arg) {
+       if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
+           (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2))
+               return -1;
+       return 0;
+}
 
-restart:
-       read_lock_bh(&table->tb6_lock);
-       for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) {
-               if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&
-                   (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) {
-                       dst_hold(&rt->dst);
-                       read_unlock_bh(&table->tb6_lock);
-                       ip6_del_rt(rt);
-                       goto restart;
-               }
-       }
-       read_unlock_bh(&table->tb6_lock);
+void rt6_purge_dflt_routers(struct net *net)
+{
+       fib6_clean_all(net, rt6_addrconf_purge, 0, NULL);
 }
 
 static void rtmsg_to_fib6_config(struct net *net,
index d5dda20bd717404a07d4dd45567b5bba23997250..1efbc6f44a6a73d727ffdb0c1a2e1d71051bcaf5 100644 (file)
@@ -212,6 +212,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
            ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
                ireq6->iif = inet6_iif(skb);
 
+       ireq->ir_mark = inet_request_mark(sk, skb);
+
        req->expires = 0UL;
        req->num_retrans = 0;
        ireq->ecn_ok            = ecn_ok;
@@ -238,7 +240,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
                final_p = fl6_update_dst(&fl6, np->opt, &final);
                fl6.saddr = ireq6->loc_addr;
                fl6.flowi6_oif = sk->sk_bound_dev_if;
-               fl6.flowi6_mark = sk->sk_mark;
+               fl6.flowi6_mark = ireq->ir_mark;
                fl6.fl6_dport = inet_rsk(req)->rmt_port;
                fl6.fl6_sport = inet_sk(sk)->inet_sport;
                security_req_classify_flow(req, flowi6_to_flowi(&fl6));
index e85c48bd404f4036b0c4e7db1e29bd6a92192f75..53a9f5a64536fd7b55199b17b323a76d80841049 100644 (file)
@@ -24,6 +24,13 @@ static ctl_table ipv6_table_template[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "fwmark_reflect",
+               .data           = &init_net.ipv6.sysctl.fwmark_reflect,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
        { }
 };
 
index 0a17ed9eaf390c4b84a6264c03697f60af9281a1..6e882dadb4f8b553549942c7c9b8525183ba10e1 100644 (file)
@@ -791,6 +791,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
        fl6.flowi6_proto = IPPROTO_TCP;
        if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL)
                fl6.flowi6_oif = inet6_iif(skb);
+       fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark);
        fl6.fl6_dport = t1->dest;
        fl6.fl6_sport = t1->source;
        security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));
@@ -999,6 +1000,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                TCP_ECN_create_request(req, skb, sock_net(sk));
 
        treq->iif = sk->sk_bound_dev_if;
+       inet_rsk(req)->ir_mark = inet_request_mark(sk, skb);
 
        /* So that link locals have meaning */
        if (!sk->sk_bound_dev_if &&