* Re: [PATCHv3 net-next 1/6] sctp: add sctp_info dump api for sctp_diag
From: Phil Sutter @ 2016-04-18 10:18 UTC (permalink / raw)
To: David Miller
Cc: lucien.xin, netdev, linux-sctp, marcelo.leitner, vyasevich,
daniel, eric.dumazet
In-Reply-To: <20160415.172858.253625178036493951.davem@davemloft.net>
On Fri, Apr 15, 2016 at 05:28:58PM -0400, David Miller wrote:
> Feedback was given here not to mix the changelog and the commit message.
>
> And I want to explicitly state that I totally and _COMPLETELY_ disagree
> with this.
>
> It is absolutely essential information and belongs in the commit message.
>
> Adding more information never hurts, so don't do this crap of putting
> things that might be useful to know after the "---", ever.
>
> Someone in the future might ask "why didn't he implement it like XXX"
> and the changelog can tell him that originally that is what was done
> and feedback was given to do it differently.
I see your point and am well aware the last word on this belongs to you.
Still I would like to explain why I disagree:
In my understanding, the changelog addresses reviewers only, so they
know what to expect or which new chunks to have another look at. If the
changelog provides valuable information beyond that, I think the mistake
was to not update the commit message accordingly.
Imagine a patchset being rerolled ten times with massive changes in
between - do you really appreciate if the changelog applies to v1 only
and people have to read through nine increments to find out what is
actually being done?
Although I'm exaggerating, one could apply the same logic to the code
changes itself and demand v1 being applied as is with each evolution
separately on top, as otherwise information is lost.
Cheers, Phil
>
> So Xin thanks for correctly putting the changelog inside of the commit
> message, so that future developers can benefit from this knowledge.
^ permalink raw reply
* Re: [PATCH] macsec: fix crypto Kconfig dependency
From: Arnd Bergmann @ 2016-04-18 10:23 UTC (permalink / raw)
To: Herbert Xu; +Cc: davem, sd, hannes, johannes, netdev, linux-kernel
In-Reply-To: <20160418080202.GA18155@gondor.apana.org.au>
On Monday 18 April 2016 16:02:02 Herbert Xu wrote:
> Arnd Bergmann <arnd@arndb.de> wrote:
> > The new MACsec driver uses the AES crypto algorithm, but can be configured
> > even if CONFIG_CRYPTO is disabled, leading to a build error:
> >
> > warning: (MAC80211 && MACSEC) selects CRYPTO_GCM which has unmet direct dependencies (CRYPTO)
> > warning: (BT && CEPH_LIB && INET && MAC802154 && MAC80211 && BLK_DEV_RBD && MACSEC && AIRO_CS && LIBIPW && HOSTAP && USB_WUSB && RTLLIB_CRYPTO_CCMP && FS_ENCRYPTION && EXT4_ENCRYPTION && CEPH_FS && BIG_KEYS && ENCRYPTED_KEYS) selects CRYPTO_AES which has unmet direct dependencies (CRYPTO)
> > crypto/built-in.o: In function `gcm_enc_copy_hash':
> > aes_generic.c:(.text+0x2b8): undefined reference to `crypto_xor'
> > aes_generic.c:(.text+0x2dc): undefined reference to `scatterwalk_map_and_copy'
> >
> > This adds an explicit 'select CRYPTO' statement the way that other
> > drivers handle it.
> >
> > Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > Fixes: c09440f7dcb3 ("macsec: introduce IEEE 802.1AE driver")
>
> Thnis patch is bogus. The build error is coming from the fact
> that GCM is built-in but CRYPTO_ALGAPI is (presumably) only built
> as a module. The patch in question does nothing to address that
> AFAICS.
No, that is not the problem.
These are the options from the randconfig file that showed the error:
# CONFIG_MODULES is not set
# CONFIG_CRYPTO is not set
CONFIG_CRYPTO_GCM=y
CONFIG_CRYPTO_AES=y
CONFIG_MACSEC=y
# CONFIG_CFG80211 is not set
As you can see, none of them are modules, and CRYPTO is completely
disabled.
> In fact this strikes me as a kbuild bug because CRYPTO_GCM already
> selects (indirectly) CRYPTO_ALGAPI so why is this happening at all?
As I tried to explain, the first two lines of the output show that
CRYPTO_GCM and CRYPTO_AES got 'select'ed while its dependencies (CRYPTO)
is not met, meaning this is the result of an incorrect Kconfig file.
Kconfig (the tool) at this point gives up, and intentionally ignores
all 'select' statements from the symbols that were wrongly selected.
I believe this is a reasonable failure mode, as following the other
selects tends to cause more problems than it solves.
As far as I can tell, my patch is correct and follows the model used by
the CONFIG_MAC80211. See below for the full output that I truncated
in order to make the changelog message more readable.
Arnd
----
[1]
warning: (MAC80211 && MACSEC) selects CRYPTO_GCM which has unmet direct dependencies (CRYPTO)
warning: (BT && CEPH_LIB && INET && MAC802154 && MAC80211 && BLK_DEV_RBD && MACSEC && AIRO_CS && LIBIPW && HOSTAP && USB_WUSB && RTLLIB_CRYPTO_CCMP && FS_ENCRYPTION && EXT4_ENCRYPTION && CEPH_FS && BIG_KEYS && ENCRYPTED_KEYS) selects CRYPTO_AES which has unmet direct dependencies (CRYPTO)
warning: (MAC80211 && MACSEC) selects CRYPTO_GCM which has unmet direct dependencies (CRYPTO)
warning: (BT && CEPH_LIB && INET && MAC802154 && MAC80211 && BLK_DEV_RBD && MACSEC && AIRO_CS && LIBIPW && HOSTAP && USB_WUSB && RTLLIB_CRYPTO_CCMP && FS_ENCRYPTION && EXT4_ENCRYPTION && CEPH_FS && BIG_KEYS && ENCRYPTED_KEYS) selects CRYPTO_AES which has unmet direct dependencies (CRYPTO)
crypto/built-in.o: In function `gcm_enc_copy_hash':
aes_generic.c:(.text+0x2b8): undefined reference to `crypto_xor'
aes_generic.c:(.text+0x2dc): undefined reference to `scatterwalk_map_and_copy'
crypto/built-in.o: In function `crypto_gcm_verify':
aes_generic.c:(.text+0x328): undefined reference to `crypto_xor'
aes_generic.c:(.text+0x34c): undefined reference to `scatterwalk_map_and_copy'
aes_generic.c:(.text+0x35c): undefined reference to `__crypto_memneq'
crypto/built-in.o: In function `crypto_gcm_init_common':
aes_generic.c:(.text+0x520): undefined reference to `scatterwalk_ffwd'
aes_generic.c:(.text+0x5dc): undefined reference to `scatterwalk_ffwd'
crypto/built-in.o: In function `crypto_rfc4106_crypt':
aes_generic.c:(.text+0x668): undefined reference to `scatterwalk_map_and_copy'
aes_generic.c:(.text+0x750): undefined reference to `scatterwalk_ffwd'
aes_generic.c:(.text+0x81c): undefined reference to `scatterwalk_ffwd'
crypto/built-in.o: In function `gcm_hash_crypt_remain_continue':
aes_generic.c:(.text+0x9c4): undefined reference to `crypto_ahash_finup'
crypto/built-in.o: In function `crypto_gcm_exit_tfm':
aes_generic.c:(.text+0xba8): undefined reference to `crypto_destroy_tfm'
aes_generic.c:(.text+0xbb8): undefined reference to `crypto_destroy_tfm'
crypto/built-in.o: In function `crypto_rfc4106_exit_tfm':
aes_generic.c:(.text+0xbc4): undefined reference to `crypto_destroy_tfm'
crypto/built-in.o: In function `crypto_rfc4106_init_tfm':
aes_generic.c:(.text+0xbd8): undefined reference to `crypto_spawn_tfm2'
crypto/built-in.o: In function `crypto_gcm_init_tfm':
aes_generic.c:(.text+0xc24): undefined reference to `crypto_spawn_tfm2'
aes_generic.c:(.text+0xc44): undefined reference to `crypto_spawn_tfm'
aes_generic.c:(.text+0xc9c): undefined reference to `crypto_destroy_tfm'
crypto/built-in.o: In function `crypto_gcm_setkey':
aes_generic.c:(.text+0xdf8): undefined reference to `crypto_ahash_setkey'
crypto/built-in.o: In function `crypto_gcm_free':
aes_generic.c:(.text+0xe48): undefined reference to `crypto_drop_spawn'
aes_generic.c:(.text+0xe50): undefined reference to `crypto_drop_spawn'
crypto/built-in.o: In function `crypto_rfc4543_free':
aes_generic.c:(.text+0xe6c): undefined reference to `crypto_drop_spawn'
crypto/built-in.o: In function `crypto_gcm_create_common':
aes_generic.c:(.text+0xe98): undefined reference to `crypto_get_attr_type'
aes_generic.c:(.text+0xed4): undefined reference to `crypto_find_alg'
aes_generic.c:(.text+0xf1c): undefined reference to `crypto_init_ahash_spawn'
aes_generic.c:(.text+0xf60): undefined reference to `crypto_grab_skcipher'
aes_generic.c:(.text+0x1060): undefined reference to `aead_register_instance'
aes_generic.c:(.text+0x1070): undefined reference to `crypto_mod_put'
aes_generic.c:(.text+0x1084): undefined reference to `crypto_drop_spawn'
aes_generic.c:(.text+0x108c): undefined reference to `crypto_drop_spawn'
aes_generic.c:(.text+0x109c): undefined reference to `crypto_ahash_type'
crypto/built-in.o: In function `crypto_gcm_base_create':
aes_generic.c:(.text+0x10dc): undefined reference to `crypto_attr_alg_name'
aes_generic.c:(.text+0x10f0): undefined reference to `crypto_attr_alg_name'
crypto/built-in.o: In function `crypto_gcm_create':
aes_generic.c:(.text+0x115c): undefined reference to `crypto_attr_alg_name'
crypto/built-in.o: In function `crypto_rfc4106_create':
aes_generic.c:(.text+0x11ec): undefined reference to `crypto_get_attr_type'
aes_generic.c:(.text+0x121c): undefined reference to `crypto_attr_alg_name'
aes_generic.c:(.text+0x1274): undefined reference to `crypto_grab_aead'
aes_generic.c:(.text+0x12c0): undefined reference to `crypto_drop_spawn'
aes_generic.c:(.text+0x1360): undefined reference to `aead_register_instance'
crypto/built-in.o: In function `crypto_rfc4543_create':
aes_generic.c:(.text+0x13b4): undefined reference to `crypto_get_attr_type'
aes_generic.c:(.text+0x13e4): undefined reference to `crypto_attr_alg_name'
aes_generic.c:(.text+0x143c): undefined reference to `crypto_grab_aead'
aes_generic.c:(.text+0x1488): undefined reference to `crypto_drop_spawn'
aes_generic.c:(.text+0x1528): undefined reference to `aead_register_instance'
crypto/built-in.o: In function `crypto_rfc4106_setauthsize':
aes_generic.c:(.text+0x1588): undefined reference to `crypto_aead_setauthsize'
crypto/built-in.o: In function `crypto_rfc4543_setauthsize':
aes_generic.c:(.text+0x15a0): undefined reference to `crypto_aead_setauthsize'
crypto/built-in.o: In function `crypto_rfc4106_setkey':
aes_generic.c:(.text+0x1608): undefined reference to `crypto_aead_setkey'
crypto/built-in.o: In function `crypto_rfc4543_setkey':
aes_generic.c:(.text+0x1690): undefined reference to `crypto_aead_setkey'
crypto/built-in.o: In function `crypto_rfc4543_exit_tfm':
aes_generic.c:(.text+0x16c8): undefined reference to `crypto_destroy_tfm'
aes_generic.c:(.text+0x16d0): undefined reference to `crypto_put_default_null_skcipher'
crypto/built-in.o: In function `crypto_rfc4543_init_tfm':
aes_generic.c:(.text+0x16e4): undefined reference to `crypto_spawn_tfm2'
aes_generic.c:(.text+0x16f8): undefined reference to `crypto_get_default_null_skcipher'
aes_generic.c:(.text+0x1744): undefined reference to `crypto_destroy_tfm'
crypto/built-in.o: In function `crypto_gcm_module_init':
aes_generic.c:(.init.text+0x40): undefined reference to `crypto_register_template'
aes_generic.c:(.init.text+0x50): undefined reference to `crypto_register_template'
aes_generic.c:(.init.text+0x60): undefined reference to `crypto_register_template'
aes_generic.c:(.init.text+0x70): undefined reference to `crypto_register_template'
aes_generic.c:(.init.text+0x80): undefined reference to `crypto_unregister_template'
aes_generic.c:(.init.text+0x88): undefined reference to `crypto_unregister_template'
aes_generic.c:(.init.text+0x90): undefined reference to `crypto_unregister_template'
crypto/built-in.o: In function `aes_init':
aes_generic.c:(.init.text+0xc4): undefined reference to `crypto_register_alg'
drivers/net/built-in.o: In function `free_rxsa':
dlci.c:(.text+0xebc): undefined reference to `crypto_destroy_tfm'
drivers/net/built-in.o: In function `free_txsa':
dlci.c:(.text+0xeec): undefined reference to `crypto_destroy_tfm'
drivers/net/built-in.o: In function `macsec_alloc_tfm':
dlci.c:(.text+0x2418): undefined reference to `crypto_alloc_aead'
dlci.c:(.text+0x2434): undefined reference to `crypto_aead_setkey'
dlci.c:(.text+0x2448): undefined reference to `crypto_destroy_tfm'
dlci.c:(.text+0x245c): undefined reference to `crypto_aead_setauthsize'
make[2]: *** [vmlinux] Error 1
make[2]: Target `_all' not remade because of errors.
make[1]: *** [sub-make] Error 2
make[1]: Target `_all' not remade because of errors.
^ permalink raw reply
* Re: [PATCH] macsec: fix crypto Kconfig dependency
From: Herbert Xu @ 2016-04-18 10:43 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: davem, sd, hannes, johannes, netdev, linux-kernel
In-Reply-To: <11585265.Dbvl2xi4u3@wuerfel>
On Mon, Apr 18, 2016 at 12:23:42PM +0200, Arnd Bergmann wrote:
>
> No, that is not the problem.
>
> These are the options from the randconfig file that showed the error:
>
> # CONFIG_MODULES is not set
> # CONFIG_CRYPTO is not set
> CONFIG_CRYPTO_GCM=y
> CONFIG_CRYPTO_AES=y
> CONFIG_MACSEC=y
> # CONFIG_CFG80211 is not set
>
> As you can see, none of them are modules, and CRYPTO is completely
> disabled.
Right, the problem is that nothing within crypto ever selects
CRYPTO since it's also used as a way of hiding the crypto menu
options.
It's kind of silly really now that IPv4 selects CRYPTO which
means that you can't really avoid seeing all those options which
most users won't care about.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH bluetooth-next 01/10] 6lowpan: add private neighbour data
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
stefan-JPH+aEBZ4P+UEJcrhfAQsw, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Alexander Aring, David S . Miller
In-Reply-To: <1460977108-4675-1-git-send-email-aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This patch will introduce a 6lowpan neighbour private data. Like the
interface private data we handle private data for generic 6lowpan and
for link-layer specific 6lowpan.
The current first use case if to save the short address for a 802.15.4
6lowpan neighbour.
Cc: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Signed-off-by: Alexander Aring <aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
include/linux/netdevice.h | 3 +--
include/net/6lowpan.h | 24 ++++++++++++++++++++++++
net/bluetooth/6lowpan.c | 2 ++
net/ieee802154/6lowpan/core.c | 12 ++++++++++++
4 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 166402a..0052c42 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1487,8 +1487,7 @@ enum netdev_priv_flags {
* @perm_addr: Permanent hw address
* @addr_assign_type: Hw address assignment type
* @addr_len: Hardware address length
- * @neigh_priv_len; Used in neigh_alloc(),
- * initialized only in atm/clip.c
+ * @neigh_priv_len; Used in neigh_alloc()
* @dev_id: Used to differentiate devices that share
* the same link layer address
* @dev_port: Used to differentiate devices that share
diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index da84cf9..61c6517 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -98,6 +98,9 @@ static inline bool lowpan_is_iphc(u8 dispatch)
#define LOWPAN_PRIV_SIZE(llpriv_size) \
(sizeof(struct lowpan_dev) + llpriv_size)
+#define LOWPAN_NEIGH_PRIV_SIZE(llneigh_priv_size) \
+ (sizeof(struct lowpan_neigh) + llneigh_priv_size)
+
enum lowpan_lltypes {
LOWPAN_LLTYPE_BTLE,
LOWPAN_LLTYPE_IEEE802154,
@@ -141,6 +144,27 @@ struct lowpan_dev {
u8 priv[0] __aligned(sizeof(void *));
};
+struct lowpan_neigh {
+ /* 6LoWPAN neigh private data */
+ /* must be last */
+ u8 priv[0] __aligned(sizeof(void *));
+};
+
+struct lowpan_802154_neigh {
+ __le16 short_addr;
+};
+
+static inline struct lowpan_neigh *lowpan_neigh(void *neigh_priv)
+{
+ return neigh_priv;
+}
+
+static inline
+struct lowpan_802154_neigh *lowpan_802154_neigh(void *neigh_priv)
+{
+ return (struct lowpan_802154_neigh *)lowpan_neigh(neigh_priv)->priv;
+}
+
static inline
struct lowpan_dev *lowpan_dev(const struct net_device *dev)
{
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 38e82dd..b7c4efa 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -833,6 +833,8 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_btle_dev **dev)
list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
spin_unlock(&devices_lock);
+ netdev->neigh_priv_len = LOWPAN_NEIGH_PRIV_SIZE(0);
+
err = lowpan_register_netdev(netdev, LOWPAN_LLTYPE_BTLE);
if (err < 0) {
BT_INFO("register_netdev failed %d", err);
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index dd085db..3162632 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -92,11 +92,21 @@ static int lowpan_stop(struct net_device *dev)
return 0;
}
+static int lowpan_neigh_construct(struct neighbour *n)
+{
+ struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n));
+
+ /* default no short_addr is available for a neighbour */
+ neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
+ return 0;
+}
+
static const struct net_device_ops lowpan_netdev_ops = {
.ndo_init = lowpan_dev_init,
.ndo_start_xmit = lowpan_xmit,
.ndo_open = lowpan_open,
.ndo_stop = lowpan_stop,
+ .ndo_neigh_construct = lowpan_neigh_construct,
};
static void lowpan_setup(struct net_device *ldev)
@@ -161,6 +171,8 @@ static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
wdev->needed_headroom;
ldev->needed_tailroom = wdev->needed_tailroom;
+ ldev->neigh_priv_len = LOWPAN_NEIGH_PRIV_SIZE(sizeof(struct lowpan_802154_neigh));
+
ret = lowpan_register_netdevice(ldev, LOWPAN_LLTYPE_IEEE802154);
if (ret < 0) {
dev_put(wdev);
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 02/10] 6lowpan: add 802.15.4 short addr slaac
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
stefan-JPH+aEBZ4P+UEJcrhfAQsw, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This patch adds the autoconfiguration if a valid 802.15.4 short address
is available for 802.15.4 6LoWPAN interfaces.
Cc: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Alexey Kuznetsov <kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
Cc: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
Cc: Hideaki YOSHIFUJI <yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
Cc: Patrick McHardy <kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
Signed-off-by: Alexander Aring <aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
include/net/addrconf.h | 3 +++
net/6lowpan/core.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
net/ipv6/addrconf.c | 5 +++--
3 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index 730d856..b1774eb 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -94,6 +94,9 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
+void addrconf_add_linklocal(struct inet6_dev *idev,
+ const struct in6_addr *addr, u32 flags);
+
static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
{
if (dev->addr_len != ETH_ALEN)
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 7a240b3..fbae31e 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <net/6lowpan.h>
+#include <net/addrconf.h>
#include "6lowpan_i.h"
@@ -72,16 +73,61 @@ void lowpan_unregister_netdev(struct net_device *dev)
}
EXPORT_SYMBOL(lowpan_unregister_netdev);
+static int addrconf_ifid_802154_6lowpan(u8 *eui, struct net_device *dev)
+{
+ struct wpan_dev *wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;
+
+ /* Set short_addr autoconfiguration if short_addr is present only */
+ if (!ieee802154_is_valid_src_short_addr(wpan_dev->short_addr))
+ return -1;
+
+ /* For either address format, all zero addresses MUST NOT be used */
+ if (wpan_dev->pan_id == cpu_to_le16(0x0000) &&
+ wpan_dev->short_addr == cpu_to_le16(0x0000))
+ return -1;
+
+ /* Alternatively, if no PAN ID is known, 16 zero bits may be used */
+ if (wpan_dev->pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
+ memset(eui, 0, 2);
+ else
+ ieee802154_le16_to_be16(eui, &wpan_dev->pan_id);
+
+ /* The "Universal/Local" (U/L) bit shall be set to zero */
+ eui[0] &= ~2;
+ eui[2] = 0;
+ eui[3] = 0xFF;
+ eui[4] = 0xFE;
+ eui[5] = 0;
+ ieee802154_le16_to_be16(&eui[6], &wpan_dev->short_addr);
+ return 0;
+}
+
static int lowpan_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct inet6_dev *idev;
+ struct in6_addr addr;
int i;
if (dev->type != ARPHRD_6LOWPAN)
return NOTIFY_DONE;
+ idev = __in6_dev_get(dev);
+ if (!idev)
+ return NOTIFY_DONE;
+
switch (event) {
+ case NETDEV_UP:
+ case NETDEV_CHANGE:
+ /* (802.15.4 6LoWPAN short address slaac handling */
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) &&
+ addrconf_ifid_802154_6lowpan(addr.s6_addr + 8, dev) == 0) {
+ __ipv6_addr_set_half(&addr.s6_addr32[0],
+ htonl(0xFE800000), 0);
+ addrconf_add_linklocal(idev, &addr, 0);
+ }
+ break;
case NETDEV_DOWN:
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 27aed1a..54e18c2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2948,8 +2948,8 @@ static void init_loopback(struct net_device *dev)
}
}
-static void addrconf_add_linklocal(struct inet6_dev *idev,
- const struct in6_addr *addr, u32 flags)
+void addrconf_add_linklocal(struct inet6_dev *idev,
+ const struct in6_addr *addr, u32 flags)
{
struct inet6_ifaddr *ifp;
u32 addr_flags = flags | IFA_F_PERMANENT;
@@ -2968,6 +2968,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev,
in6_ifa_put(ifp);
}
}
+EXPORT_SYMBOL(addrconf_add_linklocal);
static bool ipv6_reserved_interfaceid(struct in6_addr address)
{
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 03/10] 6lowpan: remove ipv6 module request
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
stefan-JPH+aEBZ4P+UEJcrhfAQsw, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Alexander Aring
In-Reply-To: <1460977108-4675-1-git-send-email-aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Since we use exported function from ipv6 kernel module we don't need to
request the module anymore to have ipv6 functionality.
Signed-off-by: Alexander Aring <aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
net/6lowpan/core.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index fbae31e..824d1bc 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -158,8 +158,6 @@ static int __init lowpan_module_init(void)
return ret;
}
- request_module_nowait("ipv6");
-
request_module_nowait("nhc_dest");
request_module_nowait("nhc_fragment");
request_module_nowait("nhc_hop");
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 04/10] ndisc: add addr_len parameter to ndisc_opt_addr_space
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
stefan-JPH+aEBZ4P+UEJcrhfAQsw, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This patch makes the address length as argument for the
ndisc_opt_addr_space function. This is necessary to handle addresses
which don't use dev->addr_len as address length.
Cc: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Alexey Kuznetsov <kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
Cc: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
Cc: Hideaki YOSHIFUJI <yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
Cc: Patrick McHardy <kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
Signed-off-by: Alexander Aring <aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
include/net/ndisc.h | 8 ++++----
net/ipv6/ndisc.c | 10 +++++-----
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 2d8edaa..ef43e88 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -127,10 +127,10 @@ static inline int ndisc_addr_option_pad(unsigned short type)
}
}
-static inline int ndisc_opt_addr_space(struct net_device *dev)
+static inline int ndisc_opt_addr_space(struct net_device *dev,
+ unsigned char addr_len)
{
- return NDISC_OPT_SPACE(dev->addr_len +
- ndisc_addr_option_pad(dev->type));
+ return NDISC_OPT_SPACE(addr_len + ndisc_addr_option_pad(dev->type));
}
static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
@@ -139,7 +139,7 @@ static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
u8 *lladdr = (u8 *)(p + 1);
int lladdrlen = p->nd_opt_len << 3;
int prepad = ndisc_addr_option_pad(dev->type);
- if (lladdrlen != ndisc_opt_addr_space(dev))
+ if (lladdrlen != ndisc_opt_addr_space(dev, dev->addr_len))
return NULL;
return lladdr + prepad;
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index c245895..69e20e3 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -154,7 +154,7 @@ static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
{
int pad = ndisc_addr_option_pad(skb->dev->type);
int data_len = skb->dev->addr_len;
- int space = ndisc_opt_addr_space(skb->dev);
+ int space = ndisc_opt_addr_space(skb->dev, skb->dev->addr_len);
u8 *opt = skb_put(skb, space);
opt[0] = type;
@@ -509,7 +509,7 @@ void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
if (!dev->addr_len)
inc_opt = 0;
if (inc_opt)
- optlen += ndisc_opt_addr_space(dev);
+ optlen += ndisc_opt_addr_space(dev, dev->addr_len);
skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
if (!skb)
@@ -574,7 +574,7 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
if (ipv6_addr_any(saddr))
inc_opt = false;
if (inc_opt)
- optlen += ndisc_opt_addr_space(dev);
+ optlen += ndisc_opt_addr_space(dev, dev->addr_len);
skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
if (!skb)
@@ -626,7 +626,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
}
#endif
if (send_sllao)
- optlen += ndisc_opt_addr_space(dev);
+ optlen += ndisc_opt_addr_space(dev, dev->addr_len);
skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
if (!skb)
@@ -1563,7 +1563,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
memcpy(ha_buf, neigh->ha, dev->addr_len);
read_unlock_bh(&neigh->lock);
ha = ha_buf;
- optlen += ndisc_opt_addr_space(dev);
+ optlen += ndisc_opt_addr_space(dev, dev->addr_len);
} else
read_unlock_bh(&neigh->lock);
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 05/10] ndisc: add addr_len parameter to ndisc_opt_addr_data
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
stefan-JPH+aEBZ4P+UEJcrhfAQsw, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This patch makes the address length as argument for the
ndisc_opt_addr_data function. This is necessary to handle addresses
which don't use dev->addr_len as address length.
Cc: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Alexey Kuznetsov <kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
Cc: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
Cc: Hideaki YOSHIFUJI <yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
Cc: Patrick McHardy <kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
Signed-off-by: Alexander Aring <aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
include/net/ndisc.h | 5 +++--
net/ipv6/ndisc.c | 11 +++++++----
net/ipv6/route.c | 2 +-
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index ef43e88..aac868e 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -134,12 +134,13 @@ static inline int ndisc_opt_addr_space(struct net_device *dev,
}
static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p,
- struct net_device *dev)
+ struct net_device *dev,
+ unsigned char addr_len)
{
u8 *lladdr = (u8 *)(p + 1);
int lladdrlen = p->nd_opt_len << 3;
int prepad = ndisc_addr_option_pad(dev->type);
- if (lladdrlen != ndisc_opt_addr_space(dev, dev->addr_len))
+ if (lladdrlen != ndisc_opt_addr_space(dev, addr_len))
return NULL;
return lladdr + prepad;
}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 69e20e3..4e91d5e 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -744,7 +744,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
}
if (ndopts.nd_opts_src_lladdr) {
- lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev);
+ lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev,
+ dev->addr_len);
if (!lladdr) {
ND_PRINTK(2, warn,
"NS: invalid link-layer address length\n");
@@ -916,7 +917,8 @@ static void ndisc_recv_na(struct sk_buff *skb)
return;
}
if (ndopts.nd_opts_tgt_lladdr) {
- lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev);
+ lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev,
+ dev->addr_len);
if (!lladdr) {
ND_PRINTK(2, warn,
"NA: invalid link-layer address length\n");
@@ -1024,7 +1026,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
if (ndopts.nd_opts_src_lladdr) {
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
- skb->dev);
+ skb->dev, skb->dev->addr_len);
if (!lladdr)
goto out;
}
@@ -1322,7 +1324,8 @@ skip_linkparms:
u8 *lladdr = NULL;
if (ndopts.nd_opts_src_lladdr) {
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr,
- skb->dev);
+ skb->dev,
+ skb->dev->addr_len);
if (!lladdr) {
ND_PRINTK(2, warn,
"RA: invalid link-layer address length\n");
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index ed44663..cc180b3 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2157,7 +2157,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
lladdr = NULL;
if (ndopts.nd_opts_tgt_lladdr) {
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
- skb->dev);
+ skb->dev, skb->dev->addr_len);
if (!lladdr) {
net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
return;
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 07/10] ipv6: introduce neighbour discovery ops
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
stefan-JPH+aEBZ4P+UEJcrhfAQsw, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This patch introduces neighbour discovery ops callback structure. The
structure contains at first receive and transmit handling for NS/NA and
userspace option field functionality.
These callback offers 6lowpan different handling, such as 802.15.4 short
address handling or RFC6775 (Neighbor Discovery Optimization for IPv6 over
6LoWPANs).
Cc: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
Cc: Alexey Kuznetsov <kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
Cc: James Morris <jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
Cc: Hideaki YOSHIFUJI <yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
Cc: Patrick McHardy <kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
Signed-off-by: Alexander Aring <aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
include/linux/netdevice.h | 3 ++
include/net/ndisc.h | 73 ++++++++++++++++++++++++++++++++++++++++++-----
net/ipv6/addrconf.c | 1 +
net/ipv6/ndisc.c | 71 +++++++++++++++++++++++++++++++--------------
net/ipv6/route.c | 2 +-
5 files changed, 121 insertions(+), 29 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 0052c42..4f1b3f2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1677,6 +1677,9 @@ struct net_device {
#ifdef CONFIG_NET_L3_MASTER_DEV
const struct l3mdev_ops *l3mdev_ops;
#endif
+#ifdef CONFIG_IPV6
+ const struct ndisc_ops *ndisc_ops;
+#endif
const struct header_ops *header_ops;
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index aac868e..5346625 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -110,7 +110,8 @@ struct ndisc_options {
#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
-struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
+struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
+ u8 *opt, int opt_len,
struct ndisc_options *ndopts);
/*
@@ -173,6 +174,70 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
return n;
}
+static inline int __ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
+{
+ return opt->nd_opt_type == ND_OPT_RDNSS ||
+ opt->nd_opt_type == ND_OPT_DNSSL;
+}
+
+struct ndisc_ops {
+ int (*is_useropt)(struct nd_opt_hdr *opt);
+ void (*send_na)(struct net_device *dev,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited,
+ bool override, bool inc_opt);
+ void (*recv_na)(struct sk_buff *skb);
+ void (*send_ns)(struct net_device *dev,
+ const struct in6_addr *solicit,
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr);
+ void (*recv_ns)(struct sk_buff *skb);
+};
+
+static inline int ndisc_is_useropt(const struct net_device *dev,
+ struct nd_opt_hdr *opt)
+{
+ if (likely(dev->ndisc_ops->is_useropt))
+ return dev->ndisc_ops->is_useropt(opt);
+ else
+ return 0;
+}
+
+static inline void ndisc_send_na(struct net_device *dev,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited, bool override,
+ bool inc_opt)
+{
+ if (likely(dev->ndisc_ops->send_na))
+ dev->ndisc_ops->send_na(dev, daddr, solicited_addr, router,
+ solicited, override, inc_opt);
+}
+
+static inline void ndisc_recv_na(struct sk_buff *skb)
+{
+ if (likely(skb->dev->ndisc_ops->recv_na))
+ skb->dev->ndisc_ops->recv_na(skb);
+}
+
+static inline void ndisc_send_ns(struct net_device *dev,
+ const struct in6_addr *solicit,
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
+{
+ if (likely(dev->ndisc_ops->send_ns))
+ dev->ndisc_ops->send_ns(dev, solicit, daddr, saddr);
+}
+
+static inline void ndisc_recv_ns(struct sk_buff *skb)
+{
+ if (likely(skb->dev->ndisc_ops->recv_ns))
+ skb->dev->ndisc_ops->recv_ns(skb);
+}
+
+void ip6_register_ndisc_ops(struct net_device *dev);
+
int ndisc_init(void);
int ndisc_late_init(void);
@@ -181,14 +246,8 @@ void ndisc_cleanup(void);
int ndisc_rcv(struct sk_buff *skb);
-void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
- const struct in6_addr *daddr, const struct in6_addr *saddr);
-
void ndisc_send_rs(struct net_device *dev,
const struct in6_addr *saddr, const struct in6_addr *daddr);
-void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
- const struct in6_addr *solicited_addr,
- bool router, bool solicited, bool override, bool inc_opt);
void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 54e18c2..a2ef04b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3266,6 +3266,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
idev = ipv6_add_dev(dev);
if (IS_ERR(idev))
return notifier_from_errno(PTR_ERR(idev));
+ ip6_register_ndisc_ops(dev);
}
break;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 176c7c4..297080a 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -185,24 +185,25 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
return cur <= end && cur->nd_opt_type == type ? cur : NULL;
}
-static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
+static inline int ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
{
- return opt->nd_opt_type == ND_OPT_RDNSS ||
- opt->nd_opt_type == ND_OPT_DNSSL;
+ return __ip6_ndisc_is_useropt(opt);
}
-static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur,
+static struct nd_opt_hdr *ndisc_next_useropt(const struct net_device *dev,
+ struct nd_opt_hdr *cur,
struct nd_opt_hdr *end)
{
if (!cur || !end || cur >= end)
return NULL;
do {
cur = ((void *)cur) + (cur->nd_opt_len << 3);
- } while (cur < end && !ndisc_is_useropt(cur));
- return cur <= end && ndisc_is_useropt(cur) ? cur : NULL;
+ } while (cur < end && !ndisc_is_useropt(dev, cur));
+ return cur <= end && ndisc_is_useropt(dev, cur) ? cur : NULL;
}
-struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
+struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
+ u8 *opt, int opt_len,
struct ndisc_options *ndopts)
{
struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
@@ -243,7 +244,7 @@ struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
break;
#endif
default:
- if (ndisc_is_useropt(nd_opt)) {
+ if (ndisc_is_useropt(dev, nd_opt)) {
ndopts->nd_useropts_end = nd_opt;
if (!ndopts->nd_useropts)
ndopts->nd_useropts = nd_opt;
@@ -479,9 +480,11 @@ static void ndisc_send_skb(struct sk_buff *skb,
rcu_read_unlock();
}
-void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
- const struct in6_addr *solicited_addr,
- bool router, bool solicited, bool override, bool inc_opt)
+static void ip6_ndisc_send_na(struct net_device *dev,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited, bool override,
+ bool inc_opt)
{
struct sk_buff *skb;
struct in6_addr tmpaddr;
@@ -555,8 +558,10 @@ static void ndisc_send_unsol_na(struct net_device *dev)
in6_dev_put(idev);
}
-void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
- const struct in6_addr *daddr, const struct in6_addr *saddr)
+static void ip6_ndisc_send_ns(struct net_device *dev,
+ const struct in6_addr *solicit,
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
{
struct sk_buff *skb;
struct in6_addr addr_buf;
@@ -702,7 +707,7 @@ static int pndisc_is_router(const void *pkey,
return ret;
}
-static void ndisc_recv_ns(struct sk_buff *skb)
+static void ip6_ndisc_recv_ns(struct sk_buff *skb)
{
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
@@ -738,7 +743,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
return;
}
- if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+ if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
ND_PRINTK(2, warn, "NS: invalid ND options\n");
return;
}
@@ -874,7 +879,7 @@ out:
in6_dev_put(idev);
}
-static void ndisc_recv_na(struct sk_buff *skb)
+static void ip6_ndisc_recv_na(struct sk_buff *skb)
{
struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
@@ -912,7 +917,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
idev->cnf.drop_unsolicited_na)
return;
- if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+ if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
ND_PRINTK(2, warn, "NS: invalid ND option\n");
return;
}
@@ -1019,7 +1024,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
goto out;
/* Parse ND options */
- if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
+ if (!ndisc_parse_options(skb->dev, rs_msg->opt, ndoptlen, &ndopts)) {
ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n");
goto out;
}
@@ -1137,7 +1142,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
return;
}
- if (!ndisc_parse_options(opt, optlen, &ndopts)) {
+ if (!ndisc_parse_options(skb->dev, opt, optlen, &ndopts)) {
ND_PRINTK(2, warn, "RA: invalid ND options\n");
return;
}
@@ -1424,7 +1429,8 @@ skip_routeinfo:
struct nd_opt_hdr *p;
for (p = ndopts.nd_useropts;
p;
- p = ndisc_next_useropt(p, ndopts.nd_useropts_end)) {
+ p = ndisc_next_useropt(skb->dev, p,
+ ndopts.nd_useropts_end)) {
ndisc_ra_useropt(skb, p);
}
}
@@ -1462,7 +1468,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
return;
}
- if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
+ if (!ndisc_parse_options(skb->dev, msg->opt, ndoptlen, &ndopts))
return;
if (!ndopts.nd_opts_rh) {
@@ -1783,6 +1789,29 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu
#endif
+static const struct ndisc_ops ip6_ndisc_ops = {
+ .is_useropt = ip6_ndisc_is_useropt,
+ .send_na = ip6_ndisc_send_na,
+ .recv_na = ip6_ndisc_recv_na,
+ .send_ns = ip6_ndisc_send_ns,
+ .recv_ns = ip6_ndisc_recv_ns,
+};
+
+void ip6_register_ndisc_ops(struct net_device *dev)
+{
+ switch (dev->type) {
+ default:
+ if (dev->ndisc_ops) {
+ ND_PRINTK(2, warn,
+ "%s: ndisc_ops already defined for interface type=%d\n",
+ __func__, dev->type);
+ } else {
+ dev->ndisc_ops = &ip6_ndisc_ops;
+ }
+ break;
+ }
+}
+
static int __net_init ndisc_net_init(struct net *net)
{
struct ipv6_pinfo *np;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index cc180b3..5fa276d 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2149,7 +2149,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
* first-hop router for the specified ICMP Destination Address.
*/
- if (!ndisc_parse_options(msg->opt, optlen, &ndopts)) {
+ if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) {
net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
return;
}
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 06/10] ndisc: add addr_len parameter to ndisc_fill_addr_option
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, stefan, mcr, werner,
linux-bluetooth, netdev, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar@pengutronix.de>
This patch makes the address length as argument for the
ndisc_fill_addr_option function. This is necessary to handle addresses
which don't use dev->addr_len as address length.
Cc: David S. Miller <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
net/ipv6/ndisc.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 4e91d5e..176c7c4 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -150,11 +150,11 @@ struct neigh_table nd_tbl = {
};
EXPORT_SYMBOL_GPL(nd_tbl);
-static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data)
+static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
+ int data_len)
{
int pad = ndisc_addr_option_pad(skb->dev->type);
- int data_len = skb->dev->addr_len;
- int space = ndisc_opt_addr_space(skb->dev, skb->dev->addr_len);
+ int space = ndisc_opt_addr_space(skb->dev, data_len);
u8 *opt = skb_put(skb, space);
opt[0] = type;
@@ -528,7 +528,7 @@ void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
if (inc_opt)
ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
- dev->dev_addr);
+ dev->dev_addr, dev->addr_len);
ndisc_send_skb(skb, daddr, src_addr);
@@ -590,7 +590,7 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
if (inc_opt)
ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
- dev->dev_addr);
+ dev->dev_addr, dev->addr_len);
ndisc_send_skb(skb, daddr, saddr);
}
@@ -641,7 +641,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
if (send_sllao)
ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
- dev->dev_addr);
+ dev->dev_addr, dev->addr_len);
ndisc_send_skb(skb, daddr, saddr);
}
@@ -1597,7 +1597,8 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
*/
if (ha)
- ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha);
+ ndisc_fill_addr_option(buff, ND_OPT_TARGET_LL_ADDR, ha,
+ dev->addr_len);
/*
* build redirect option and copy skb over to the new packet.
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 00/10] 6lowpan: introduce basic 6lowpan-nd
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, stefan, mcr, werner,
linux-bluetooth, netdev, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
Hi,
this patch series introduces a layer for IPv6 neighbour discovery. At first
it introduce the "ndisc_ops" to run a different handling for recv/send of
NA/NS messages. The use case for such ndisc operation is RFC 6775 [0].
Which describes a different neighbour discovery handling for 6LoWPAN networks.
I didn't implement RFC 6775 in this patch series, but introduce callback
structure for replace different functions in ndisc implementation might be
the right direction.
Another use case would be RFC 7400 [1] which describes a new option field to
getting capabilities of 6LoWPAN next header compression methods.
What I implemented is a necessary functionality to handle short address for
802.15.4 6LoWPAN networks. The L2-Layer "802.15.4" can have two different
link-layer addresses which can be used mixed at the same time inside 802.15.4
networks. To deal with such behaviour in ndisc, it is defined at RFC 4944 [2].
The bad news is, that I saw different handling of such handling. What Linux
will do is to add two source/target address information option fields, each
with different length, if short address is valid (can also not be given).
Example:
- WPAN interface address settings
- extended addr (must always be there)
- short addr (0xfffe or 0xffff -> invalid)
Will add an extended addr to source/target address information option field.
If short addr is in some valid range, then both address will be added to
the option fields. Indicated are these different address types by the length
field (extended -> length=2, short -> length=1), according to [1].
The tested 6LoWPAN implementation (RIOT-OS) allows only one source/target
option field which is short XOR extended, otherwise it will be dropped.
There is some lack of information there [2] and I don't know how do deal with
it right, maybe we need to update the implementation there if it's really
wrong.
To save such information for each neighbour we use the already implemented
neighbour private data which some casting strategy for 6LoWPAN and 6LoWPAN
link-layer specific data e.g. 802.15.4 short address handling.
Additional I implemented to add 6CO to the is_useropt callback in case of
6LoWPAN interface. The 6CO option will currently parsed in userspace which
are placed in RA-Messages.
The ndisc_ops are not finished yet, of course we need handling for RS messages
to place the 802.15.4 short address there as well and then also processing
of RA messages for the 802.15.4 SLLAO option field.
- Alex
[0] https://tools.ietf.org/html/rfc6775
[1] https://tools.ietf.org/html/rfc7400#section-3.3
[2] https://tools.ietf.org/html/rfc4944#section-8
Cc: David S. Miller <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Alexander Aring (10):
6lowpan: add private neighbour data
6lowpan: add 802.15.4 short addr slaac
6lowpan: remove ipv6 module request
ndisc: add addr_len parameter to ndisc_opt_addr_space
ndisc: add addr_len parameter to ndisc_opt_addr_data
ndisc: add addr_len parameter to ndisc_fill_addr_option
ipv6: introduce neighbour discovery ops
ipv6: export ndisc functions
6lowpan: introduce 6lowpan-nd
6lowpan: add support for 802.15.4 short addr handling
include/linux/netdevice.h | 6 +-
include/net/6lowpan.h | 24 ++
include/net/addrconf.h | 3 +
include/net/ndisc.h | 101 ++++++-
net/6lowpan/6lowpan_i.h | 2 +
net/6lowpan/Makefile | 2 +-
net/6lowpan/core.c | 50 +++-
net/6lowpan/iphc.c | 167 +++++++++--
net/6lowpan/ndisc.c | 633 ++++++++++++++++++++++++++++++++++++++++++
net/bluetooth/6lowpan.c | 2 +
net/ieee802154/6lowpan/core.c | 12 +
net/ieee802154/6lowpan/tx.c | 107 ++++---
net/ipv6/addrconf.c | 7 +-
net/ipv6/ndisc.c | 132 +++++----
net/ipv6/route.c | 4 +-
15 files changed, 1094 insertions(+), 158 deletions(-)
create mode 100644 net/6lowpan/ndisc.c
--
2.8.0
^ permalink raw reply
* [PATCH bluetooth-next 08/10] ipv6: export ndisc functions
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, stefan, mcr, werner,
linux-bluetooth, netdev, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar@pengutronix.de>
This patch exports some neighbour discovery functions which can be used
by 6lowpan neighbour discovery ops functionality then.
Cc: David S. Miller <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
include/net/ndisc.h | 16 ++++++++++++++++
net/ipv6/addrconf.c | 1 +
net/ipv6/ndisc.c | 28 ++++++++++------------------
3 files changed, 27 insertions(+), 18 deletions(-)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 5346625..25ce092 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -53,6 +53,15 @@ enum {
#include <net/neighbour.h>
+/* Set to 3 to get tracing... */
+#define ND_DEBUG 1
+
+#define ND_PRINTK(val, level, fmt, ...) \
+do { \
+ if (val <= ND_DEBUG) \
+ net_##level##_ratelimited(fmt, ##__VA_ARGS__); \
+} while (0)
+
struct ctl_table;
struct inet6_dev;
struct net_device;
@@ -244,6 +253,13 @@ int ndisc_late_init(void);
void ndisc_late_cleanup(void);
void ndisc_cleanup(void);
+void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
+ int data_len);
+struct sk_buff *ndisc_alloc_skb(struct net_device *dev, int len);
+void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
+ const struct in6_addr *saddr);
+int pndisc_is_router(const void *pkey, struct net_device *dev);
+
int ndisc_rcv(struct sk_buff *skb);
void ndisc_send_rs(struct net_device *dev,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a2ef04b..8f05ef8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1775,6 +1775,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *add
return result;
}
+EXPORT_SYMBOL(ipv6_get_ifaddr);
/* Gets referenced address, destroys ifaddr */
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 297080a..dc8bfec 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -73,15 +73,6 @@
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
-/* Set to 3 to get tracing... */
-#define ND_DEBUG 1
-
-#define ND_PRINTK(val, level, fmt, ...) \
-do { \
- if (val <= ND_DEBUG) \
- net_##level##_ratelimited(fmt, ##__VA_ARGS__); \
-} while (0)
-
static u32 ndisc_hash(const void *pkey,
const struct net_device *dev,
__u32 *hash_rnd);
@@ -150,8 +141,8 @@ struct neigh_table nd_tbl = {
};
EXPORT_SYMBOL_GPL(nd_tbl);
-static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
- int data_len)
+void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
+ int data_len)
{
int pad = ndisc_addr_option_pad(skb->dev->type);
int space = ndisc_opt_addr_space(skb->dev, data_len);
@@ -171,6 +162,7 @@ static void ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data,
if (space > 0)
memset(opt, 0, space);
}
+EXPORT_SYMBOL(ndisc_fill_addr_option);
static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
struct nd_opt_hdr *end)
@@ -378,8 +370,7 @@ static void pndisc_destructor(struct pneigh_entry *n)
ipv6_dev_mc_dec(dev, &maddr);
}
-static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
- int len)
+struct sk_buff *ndisc_alloc_skb(struct net_device *dev, int len)
{
int hlen = LL_RESERVED_SPACE(dev);
int tlen = dev->needed_tailroom;
@@ -406,6 +397,7 @@ static struct sk_buff *ndisc_alloc_skb(struct net_device *dev,
return skb;
}
+EXPORT_SYMBOL(ndisc_alloc_skb);
static void ip6_nd_hdr(struct sk_buff *skb,
const struct in6_addr *saddr,
@@ -428,9 +420,8 @@ static void ip6_nd_hdr(struct sk_buff *skb,
hdr->daddr = *daddr;
}
-static void ndisc_send_skb(struct sk_buff *skb,
- const struct in6_addr *daddr,
- const struct in6_addr *saddr)
+void ndisc_send_skb(struct sk_buff *skb, const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
{
struct dst_entry *dst = skb_dst(skb);
struct net *net = dev_net(skb->dev);
@@ -479,6 +470,7 @@ static void ndisc_send_skb(struct sk_buff *skb,
rcu_read_unlock();
}
+EXPORT_SYMBOL(ndisc_send_skb);
static void ip6_ndisc_send_na(struct net_device *dev,
const struct in6_addr *daddr,
@@ -692,8 +684,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
}
}
-static int pndisc_is_router(const void *pkey,
- struct net_device *dev)
+int pndisc_is_router(const void *pkey, struct net_device *dev)
{
struct pneigh_entry *n;
int ret = -1;
@@ -706,6 +697,7 @@ static int pndisc_is_router(const void *pkey,
return ret;
}
+EXPORT_SYMBOL(pndisc_is_router);
static void ip6_ndisc_recv_ns(struct sk_buff *skb)
{
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 09/10] 6lowpan: introduce 6lowpan-nd
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, stefan, mcr, werner,
linux-bluetooth, netdev, Alexander Aring, David S . Miller,
Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <1460977108-4675-1-git-send-email-aar@pengutronix.de>
This patch introduce different 6lowpan handling for receive and transmit
NS/NA messages for the ipv6 neighbour discovery. The first use-case is
for supporting 802.15.4 short addresses inside the option fields and
handling for RFC6775 6CO option field as userspace option.
Future handling:
Also add RS/RA(processing) for 802.15.4 short addresses and handle
RFC6775, which requires more 6lowpan specific handling for ipv6 neighbour
discovery implementation.
Cc: David S. Miller <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
include/net/ndisc.h | 1 +
net/6lowpan/6lowpan_i.h | 2 +
net/6lowpan/Makefile | 2 +-
net/6lowpan/core.c | 2 +
net/6lowpan/ndisc.c | 633 ++++++++++++++++++++++++++++++++++++++++++++++++
net/ipv6/ndisc.c | 3 +
6 files changed, 642 insertions(+), 1 deletion(-)
create mode 100644 net/6lowpan/ndisc.c
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 25ce092..a884c81 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -35,6 +35,7 @@ enum {
ND_OPT_ROUTE_INFO = 24, /* RFC4191 */
ND_OPT_RDNSS = 25, /* RFC5006 */
ND_OPT_DNSSL = 31, /* RFC6106 */
+ ND_OPT_6CO = 34, /* RFC6775 */
__ND_OPT_MAX
};
diff --git a/net/6lowpan/6lowpan_i.h b/net/6lowpan/6lowpan_i.h
index 97ecc27..8b01774 100644
--- a/net/6lowpan/6lowpan_i.h
+++ b/net/6lowpan/6lowpan_i.h
@@ -12,6 +12,8 @@ static inline bool lowpan_is_ll(const struct net_device *dev,
return lowpan_dev(dev)->lltype == lltype;
}
+void lowpan_register_ndisc_ops(struct net_device *dev);
+
#ifdef CONFIG_6LOWPAN_DEBUGFS
int lowpan_dev_debugfs_init(struct net_device *dev);
void lowpan_dev_debugfs_exit(struct net_device *dev);
diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile
index e44f3bf..12d131a 100644
--- a/net/6lowpan/Makefile
+++ b/net/6lowpan/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_6LOWPAN) += 6lowpan.o
-6lowpan-y := core.o iphc.o nhc.o
+6lowpan-y := core.o iphc.o nhc.o ndisc.o
6lowpan-$(CONFIG_6LOWPAN_DEBUGFS) += debugfs.o
#rfc6282 nhcs
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 824d1bc..e7a370e 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -34,6 +34,8 @@ int lowpan_register_netdevice(struct net_device *dev,
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
lowpan_dev(dev)->ctx.table[i].id = i;
+ lowpan_register_ndisc_ops(dev);
+
ret = register_netdevice(dev);
if (ret < 0)
return ret;
diff --git a/net/6lowpan/ndisc.c b/net/6lowpan/ndisc.c
new file mode 100644
index 0000000..b6dc244
--- /dev/null
+++ b/net/6lowpan/ndisc.c
@@ -0,0 +1,633 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 <net/6lowpan.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+#include <net/ndisc.h>
+
+#include "6lowpan_i.h"
+
+struct lowpan_ndisc_options {
+ struct nd_opt_hdr *nd_opt_array[ND_OPT_TARGET_LL_ADDR + 1];
+#ifdef CONFIG_IEEE802154_6LOWPAN
+ struct nd_opt_hdr *nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR + 1];
+#endif
+};
+
+#define nd_802154_opts_src_lladdr nd_802154_opt_array[ND_OPT_SOURCE_LL_ADDR]
+#define nd_802154_opts_tgt_lladdr nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR]
+
+#define NDISC_802154_EXTENDED_ADDR_LENGTH 2
+#define NDISC_802154_SHORT_ADDR_LENGTH 1
+
+#ifdef CONFIG_IEEE802154_6LOWPAN
+static void lowpan_ndisc_802154_neigh_update(struct neighbour *n, void *priv,
+ bool override)
+{
+ struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n));
+
+ if (!override)
+ return;
+
+ write_lock_bh(&n->lock);
+ if (priv)
+ ieee802154_be16_to_le16(&neigh->short_addr, priv);
+ else
+ neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
+ write_unlock_bh(&n->lock);
+}
+
+static inline int lowpan_ndisc_802154_short_addr_space(struct net_device *dev)
+{
+ struct wpan_dev *wpan_dev;
+ int addr_space = 0;
+
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154)) {
+ wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;
+
+ if (ieee802154_is_valid_src_short_addr(wpan_dev->short_addr))
+ addr_space = ndisc_opt_addr_space(dev, IEEE802154_SHORT_ADDR_LEN);
+ }
+
+ return addr_space;
+}
+
+static inline void
+lowpan_ndisc_802154_short_addr_option(struct net_device *dev,
+ struct sk_buff *skb, int type)
+{
+ struct wpan_dev *wpan_dev;
+ __be16 short_addr;
+
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154)) {
+ wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;
+
+ if (ieee802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
+ ieee802154_le16_to_be16(&short_addr,
+ &wpan_dev->short_addr);
+ ndisc_fill_addr_option(skb, type, &short_addr,
+ IEEE802154_SHORT_ADDR_LEN);
+ }
+ }
+}
+#else
+static void
+lowpan_ndisc_802154_neigh_update(struct neighbour *n, void *priv,
+ bool override) { }
+
+static inline void
+lowpan_ndisc_802154_short_addr_option(struct net_device *dev,
+ struct sk_buff *skb,
+ int type) { }
+
+static inline int lowpan_ndisc_802154_short_addr_space(struct net_device *dev)
+{
+ return 0;
+}
+#endif
+
+static void lowpan_ndisc_parse_addr_options(const struct net_device *dev,
+ struct lowpan_ndisc_options *ndopts,
+ struct nd_opt_hdr *nd_opt)
+{
+ switch (nd_opt->nd_opt_len) {
+ case NDISC_802154_EXTENDED_ADDR_LENGTH:
+ if (ndopts->nd_opt_array[nd_opt->nd_opt_type])
+ ND_PRINTK(2, warn,
+ "%s: duplicated extended addr ND6 option found: type=%d\n",
+ __func__, nd_opt->nd_opt_type);
+ else
+ ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
+ break;
+#ifdef CONFIG_IEEE802154_6LOWPAN
+ case NDISC_802154_SHORT_ADDR_LENGTH:
+ /* only valid on 802.15.4 */
+ if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154)) {
+ ND_PRINTK(2, warn,
+ "%s: invalid length detected: type=%d\n",
+ __func__, nd_opt->nd_opt_type);
+ break;
+ }
+
+ if (ndopts->nd_802154_opt_array[nd_opt->nd_opt_type])
+ ND_PRINTK(2, warn,
+ "%s: duplicated short addr ND6 option found: type=%d\n",
+ __func__, nd_opt->nd_opt_type);
+ else
+ ndopts->nd_802154_opt_array[nd_opt->nd_opt_type] = nd_opt;
+ break;
+#endif
+ default:
+ ND_PRINTK(2, warn,
+ "%s: invalid length detected: type=%d\n",
+ __func__, nd_opt->nd_opt_type);
+ break;
+ }
+}
+
+static struct lowpan_ndisc_options *
+lowpan_ndisc_parse_options(const struct net_device *dev, u8 *opt, int opt_len,
+ struct lowpan_ndisc_options *ndopts)
+{
+ struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt;
+
+ if (!nd_opt || opt_len < 0 || !ndopts)
+ return NULL;
+
+ memset(ndopts, 0, sizeof(*ndopts));
+
+ while (opt_len) {
+ int l;
+
+ if (opt_len < sizeof(struct nd_opt_hdr))
+ return NULL;
+
+ l = nd_opt->nd_opt_len << 3;
+ if (opt_len < l || l == 0)
+ return NULL;
+
+ switch (nd_opt->nd_opt_type) {
+ case ND_OPT_SOURCE_LL_ADDR:
+ case ND_OPT_TARGET_LL_ADDR:
+ lowpan_ndisc_parse_addr_options(dev, ndopts, nd_opt);
+ break;
+ default:
+ /* Unknown options must be silently ignored,
+ * to accommodate future extension to the
+ * protocol.
+ */
+ ND_PRINTK(2, notice,
+ "%s: ignored unsupported option; type=%d, len=%d\n",
+ __func__,
+ nd_opt->nd_opt_type,
+ nd_opt->nd_opt_len);
+ }
+
+ opt_len -= l;
+ nd_opt = ((void *)nd_opt) + l;
+ }
+
+ return ndopts;
+}
+
+static void lowpan_ndisc_send_na(struct net_device *dev,
+ const struct in6_addr *daddr,
+ const struct in6_addr *solicited_addr,
+ bool router, bool solicited, bool override,
+ bool inc_opt)
+{
+ struct sk_buff *skb;
+ struct in6_addr tmpaddr;
+ struct inet6_ifaddr *ifp;
+ const struct in6_addr *src_addr;
+ struct nd_msg *msg;
+ int optlen = 0;
+
+ /* for anycast or proxy, solicited_addr != src_addr */
+ ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
+ if (ifp) {
+ src_addr = solicited_addr;
+ if (ifp->flags & IFA_F_OPTIMISTIC)
+ override = false;
+ inc_opt |= ifp->idev->cnf.force_tllao;
+ in6_ifa_put(ifp);
+ } else {
+ if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
+ inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
+ &tmpaddr))
+ return;
+ src_addr = &tmpaddr;
+ }
+
+ if (!dev->addr_len)
+ inc_opt = 0;
+ if (inc_opt) {
+ optlen += ndisc_opt_addr_space(dev, dev->addr_len);
+ optlen += lowpan_ndisc_802154_short_addr_space(dev);
+ }
+
+ skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
+ if (!skb)
+ return;
+
+ msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
+ *msg = (struct nd_msg) {
+ .icmph = {
+ .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
+ .icmp6_router = router,
+ .icmp6_solicited = solicited,
+ .icmp6_override = override,
+ },
+ .target = *solicited_addr,
+ };
+
+ if (inc_opt) {
+ ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR,
+ dev->dev_addr, dev->addr_len);
+ lowpan_ndisc_802154_short_addr_option(dev, skb,
+ ND_OPT_TARGET_LL_ADDR);
+ }
+
+ ndisc_send_skb(skb, daddr, src_addr);
+}
+
+static void lowpan_ndisc_recv_na(struct sk_buff *skb)
+{
+ struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
+ struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+ const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
+ u8 *lladdr = NULL;
+ u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
+ offsetof(struct nd_msg, opt));
+ struct lowpan_ndisc_options ndopts;
+ struct net_device *dev = skb->dev;
+ struct inet6_dev *idev = __in6_dev_get(dev);
+ struct inet6_ifaddr *ifp;
+ struct neighbour *neigh;
+ u8 *lladdr_short = NULL;
+
+ if (skb->len < sizeof(struct nd_msg)) {
+ ND_PRINTK(2, warn, "NA: packet too short\n");
+ return;
+ }
+
+ if (ipv6_addr_is_multicast(&msg->target)) {
+ ND_PRINTK(2, warn, "NA: target address is multicast\n");
+ return;
+ }
+
+ if (ipv6_addr_is_multicast(daddr) &&
+ msg->icmph.icmp6_solicited) {
+ ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n");
+ return;
+ }
+
+ /* For some 802.11 wireless deployments (and possibly other networks),
+ * there will be a NA proxy and unsolicitd packets are attacks
+ * and thus should not be accepted.
+ */
+ if (!msg->icmph.icmp6_solicited && idev &&
+ idev->cnf.drop_unsolicited_na)
+ return;
+
+ if (!lowpan_ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
+ ND_PRINTK(2, warn, "NS: invalid ND option\n");
+ return;
+ }
+ if (ndopts.nd_opts_tgt_lladdr) {
+ lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev,
+ dev->addr_len);
+ if (!lladdr) {
+ ND_PRINTK(2, warn,
+ "NA: invalid link-layer address length\n");
+ return;
+ }
+ }
+#ifdef CONFIG_IEEE802154_6LOWPAN
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) &&
+ ndopts.nd_802154_opts_tgt_lladdr) {
+ lladdr_short = ndisc_opt_addr_data(ndopts.nd_802154_opts_tgt_lladdr,
+ dev, IEEE802154_SHORT_ADDR_LEN);
+ if (!lladdr_short) {
+ ND_PRINTK(2, warn,
+ "NA: invalid short link-layer address length\n");
+ return;
+ }
+ }
+#endif
+ ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
+ if (ifp) {
+ if (skb->pkt_type != PACKET_LOOPBACK &&
+ (ifp->flags & IFA_F_TENTATIVE)) {
+ addrconf_dad_failure(ifp);
+ return;
+ }
+ /* What should we make now? The advertisement
+ * is invalid, but ndisc specs say nothing
+ * about it. It could be misconfiguration, or
+ * an smart proxy agent tries to help us :-)
+ *
+ * We should not print the error if NA has been
+ * received from loopback - it is just our own
+ * unsolicited advertisement.
+ */
+ if (skb->pkt_type != PACKET_LOOPBACK)
+ ND_PRINTK(1, warn,
+ "NA: someone advertises our address %pI6 on %s!\n",
+ &ifp->addr, ifp->idev->dev->name);
+ in6_ifa_put(ifp);
+ return;
+ }
+ neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
+
+ if (neigh) {
+ u8 old_flags = neigh->flags;
+ struct net *net = dev_net(dev);
+
+ if (neigh->nud_state & NUD_FAILED)
+ goto out;
+
+ /* Don't update the neighbor cache entry on a proxy NA from
+ * ourselves because either the proxied node is off link or it
+ * has already sent a NA to us.
+ */
+ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
+ net->ipv6.devconf_all->forwarding &&
+ net->ipv6.devconf_all->proxy_ndp &&
+ pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
+ /* XXX: idev->cnf.proxy_ndp */
+ goto out;
+ }
+
+ neigh_update(neigh, lladdr,
+ msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
+ NEIGH_UPDATE_F_WEAK_OVERRIDE |
+ (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0) |
+ NEIGH_UPDATE_F_OVERRIDE_ISROUTER |
+ (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0));
+
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
+ lowpan_ndisc_802154_neigh_update(neigh, lladdr_short,
+ msg->icmph.icmp6_override);
+
+ if ((old_flags & ~neigh->flags) & NTF_ROUTER) {
+ /* Change: router to host */
+ rt6_clean_tohost(dev_net(dev), saddr);
+ }
+
+out:
+ neigh_release(neigh);
+ }
+}
+
+static void lowpan_ndisc_send_ns(struct net_device *dev,
+ const struct in6_addr *solicit,
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
+{
+ struct sk_buff *skb;
+ struct in6_addr addr_buf;
+ int inc_opt = dev->addr_len;
+ int optlen = 0;
+ struct nd_msg *msg;
+
+ if (!saddr) {
+ if (ipv6_get_lladdr(dev, &addr_buf,
+ (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)))
+ return;
+ saddr = &addr_buf;
+ }
+
+ if (ipv6_addr_any(saddr))
+ inc_opt = false;
+ if (inc_opt) {
+ optlen += ndisc_opt_addr_space(dev, dev->addr_len);
+ optlen += lowpan_ndisc_802154_short_addr_space(dev);
+ }
+
+ skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
+ if (!skb)
+ return;
+
+ msg = (struct nd_msg *)skb_put(skb, sizeof(*msg));
+ *msg = (struct nd_msg) {
+ .icmph = {
+ .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION,
+ },
+ .target = *solicit,
+ };
+
+ if (inc_opt) {
+ ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
+ dev->dev_addr, dev->addr_len);
+ lowpan_ndisc_802154_short_addr_option(dev, skb,
+ ND_OPT_SOURCE_LL_ADDR);
+ }
+
+ ndisc_send_skb(skb, daddr, saddr);
+}
+
+static void lowpan_ndisc_recv_ns(struct sk_buff *skb)
+{
+ struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb);
+ const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr;
+ const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr;
+ u8 *lladdr = NULL;
+ u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) +
+ offsetof(struct nd_msg, opt));
+ struct lowpan_ndisc_options ndopts;
+ struct net_device *dev = skb->dev;
+ struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev = NULL;
+ struct neighbour *neigh;
+ int dad = ipv6_addr_any(saddr);
+ bool inc;
+ int is_router = -1;
+ u8 *lladdr_short = NULL;
+
+ if (skb->len < sizeof(struct nd_msg)) {
+ ND_PRINTK(2, warn, "NS: packet too short\n");
+ return;
+ }
+
+ if (ipv6_addr_is_multicast(&msg->target)) {
+ ND_PRINTK(2, warn, "NS: multicast target address\n");
+ return;
+ }
+
+ /* RFC2461 7.1.1:
+ * DAD has to be destined for solicited node multicast address.
+ */
+ if (dad && !ipv6_addr_is_solict_mult(daddr)) {
+ ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
+ return;
+ }
+
+ if (!lowpan_ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) {
+ ND_PRINTK(2, warn, "NS: invalid ND options\n");
+ return;
+ }
+
+ if (ndopts.nd_opts_src_lladdr) {
+ lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev,
+ dev->addr_len);
+ if (!lladdr) {
+ ND_PRINTK(2, warn,
+ "NS: invalid link-layer address length\n");
+ return;
+ }
+
+ /* RFC2461 7.1.1:
+ * If the IP source address is the unspecified address,
+ * there MUST NOT be source link-layer address option
+ * in the message.
+ */
+ if (dad) {
+ ND_PRINTK(2, warn,
+ "NS: bad DAD packet (link-layer address option)\n");
+ return;
+ }
+ }
+
+#ifdef CONFIG_IEEE802154_6LOWPAN
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) &&
+ ndopts.nd_802154_opts_src_lladdr) {
+ lladdr_short = ndisc_opt_addr_data(ndopts.nd_802154_opts_src_lladdr,
+ dev, IEEE802154_SHORT_ADDR_LEN);
+ if (!lladdr_short) {
+ ND_PRINTK(2, warn,
+ "NS: invalid short link-layer address length\n");
+ return;
+ }
+
+ /* RFC2461 7.1.1:
+ * If the IP source address is the unspecified address,
+ * there MUST NOT be source link-layer address option
+ * in the message.
+ */
+ if (dad) {
+ ND_PRINTK(2, warn,
+ "NS: bad DAD packet (short link-layer address option)\n");
+ return;
+ }
+ }
+#endif
+
+ inc = ipv6_addr_is_multicast(daddr);
+
+ ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
+ if (ifp) {
+have_ifp:
+ if (ifp->flags & (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)) {
+ if (dad) {
+ /* We are colliding with another node
+ * who is doing DAD
+ * so fail our DAD process
+ */
+ addrconf_dad_failure(ifp);
+ return;
+ }
+
+ /* This is not a dad solicitation.
+ * If we are an optimistic node,
+ * we should respond.
+ * Otherwise, we should ignore it.
+ */
+ if (!(ifp->flags & IFA_F_OPTIMISTIC))
+ goto out;
+ }
+
+ idev = ifp->idev;
+ } else {
+ struct net *net = dev_net(dev);
+
+ /* perhaps an address on the master device */
+ if (netif_is_l3_slave(dev)) {
+ struct net_device *mdev;
+
+ mdev = netdev_master_upper_dev_get_rcu(dev);
+ if (mdev) {
+ ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1);
+ if (ifp)
+ goto have_ifp;
+ }
+ }
+
+ idev = in6_dev_get(dev);
+ if (!idev) {
+ /* XXX: count this drop? */
+ return;
+ }
+
+ if (ipv6_chk_acast_addr(net, dev, &msg->target) ||
+ (idev->cnf.forwarding &&
+ (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) &&
+ (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
+ if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
+ skb->pkt_type != PACKET_HOST &&
+ inc &&
+ NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) {
+ /* for anycast or proxy,
+ * sender should delay its response
+ * by a random time between 0 and
+ * MAX_ANYCAST_DELAY_TIME seconds.
+ * (RFC2461) -- yoshfuji
+ */
+ struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
+
+ if (n)
+ pneigh_enqueue(&nd_tbl, idev->nd_parms,
+ n);
+ goto out;
+ }
+ } else {
+ goto out;
+ }
+ }
+
+ if (is_router < 0)
+ is_router = idev->cnf.forwarding;
+
+ if (dad) {
+ ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target,
+ !!is_router, false, (ifp != NULL), true);
+ goto out;
+ }
+
+ if (inc)
+ NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast);
+ else
+ NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast);
+
+ /* update / create cache entry
+ * for the source address
+ */
+ neigh = __neigh_lookup(&nd_tbl, saddr, dev,
+ !inc || lladdr || !dev->addr_len);
+ if (neigh) {
+ neigh_update(neigh, lladdr, NUD_STALE,
+ NEIGH_UPDATE_F_WEAK_OVERRIDE |
+ NEIGH_UPDATE_F_OVERRIDE);
+ if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
+ lowpan_ndisc_802154_neigh_update(neigh, lladdr_short,
+ true);
+ }
+ if (neigh || !dev->header_ops) {
+ ndisc_send_na(dev, saddr, &msg->target, !!is_router,
+ true, (ifp != NULL && inc), inc);
+ if (neigh)
+ neigh_release(neigh);
+ }
+
+out:
+ if (ifp)
+ in6_ifa_put(ifp);
+ else
+ in6_dev_put(idev);
+}
+
+static inline int lowpan_ndisc_is_useropt(struct nd_opt_hdr *opt)
+{
+ return __ip6_ndisc_is_useropt(opt) || opt->nd_opt_type == ND_OPT_6CO;
+}
+
+static const struct ndisc_ops lowpan_ndisc_ops = {
+ .is_useropt = lowpan_ndisc_is_useropt,
+ .send_na = lowpan_ndisc_send_na,
+ .recv_na = lowpan_ndisc_recv_na,
+ .send_ns = lowpan_ndisc_send_ns,
+ .recv_ns = lowpan_ndisc_recv_ns,
+};
+
+void lowpan_register_ndisc_ops(struct net_device *dev)
+{
+ dev->ndisc_ops = &lowpan_ndisc_ops;
+}
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index dc8bfec..9d7f228 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1792,6 +1792,9 @@ static const struct ndisc_ops ip6_ndisc_ops = {
void ip6_register_ndisc_ops(struct net_device *dev)
{
switch (dev->type) {
+ case ARPHRD_6LOWPAN:
+ /* will be assigned while lowpan interface register */
+ break;
default:
if (dev->ndisc_ops) {
ND_PRINTK(2, warn,
--
2.8.0
^ permalink raw reply related
* [PATCH bluetooth-next 10/10] 6lowpan: add support for 802.15.4 short addr handling
From: Alexander Aring @ 2016-04-18 10:58 UTC (permalink / raw)
To: linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, stefan, mcr, werner,
linux-bluetooth, netdev, Alexander Aring
In-Reply-To: <1460977108-4675-1-git-send-email-aar@pengutronix.de>
This patch adds necessary handling for use the short address for
802.15.4 6lowpan. It contains support for IPHC address compression
and new matching algorithmn to decide which link layer address will be
used for 802.15.4 frame.
Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
net/6lowpan/iphc.c | 167 ++++++++++++++++++++++++++++++++++++--------
net/ieee802154/6lowpan/tx.c | 107 ++++++++++++++--------------
2 files changed, 189 insertions(+), 85 deletions(-)
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 8501dd5..aca38dc 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -761,22 +761,75 @@ static const u8 lowpan_iphc_dam_to_sam_value[] = {
[LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11,
};
-static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct in6_addr *ipaddr,
+static inline bool
+lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
+ const struct lowpan_iphc_ctx *ctx,
+ const void *lladdr)
+{
+ const struct ieee802154_addr *addr = lladdr;
+ unsigned char extended_addr[EUI64_ADDR_LEN];
+ struct in6_addr tmp = {};
+ bool lladdr_compress = false;
+
+ switch (addr->mode) {
+ case IEEE802154_ADDR_LONG:
+ ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
+ /* check for SAM/DAM = 11 */
+ memcpy(&tmp.s6_addr[8], &extended_addr, EUI64_ADDR_LEN);
+ /* second bit-flip (Universe/Local) is done according RFC2464 */
+ tmp.s6_addr[8] ^= 0x02;
+ /* context information are always used */
+ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+ if (ipv6_addr_equal(&tmp, ipaddr))
+ lladdr_compress = true;
+ break;
+ case IEEE802154_ADDR_SHORT:
+ tmp.s6_addr[11] = 0xFF;
+ tmp.s6_addr[12] = 0xFE;
+ ieee802154_le16_to_be16(&tmp.s6_addr16[7],
+ &addr->short_addr);
+ /* context information are always used */
+ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+ if (ipv6_addr_equal(&tmp, ipaddr))
+ lladdr_compress = true;
+ break;
+ default:
+ /* should never handled and filtered by 802154 6lowpan */
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ return lladdr_compress;
+}
+
+static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
+ const struct in6_addr *ipaddr,
const struct lowpan_iphc_ctx *ctx,
const unsigned char *lladdr, bool sam)
{
struct in6_addr tmp = {};
u8 dam;
- /* check for SAM/DAM = 11 */
- memcpy(&tmp.s6_addr[8], lladdr, 8);
- /* second bit-flip (Universe/Local) is done according RFC2464 */
- tmp.s6_addr[8] ^= 0x02;
- /* context information are always used */
- ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
- if (ipv6_addr_equal(&tmp, ipaddr)) {
- dam = LOWPAN_IPHC_DAM_11;
- goto out;
+ switch (lowpan_dev(dev)->lltype) {
+ case LOWPAN_LLTYPE_IEEE802154:
+ if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx,
+ lladdr)) {
+ dam = LOWPAN_IPHC_DAM_11;
+ goto out;
+ }
+ break;
+ default:
+ /* check for SAM/DAM = 11 */
+ memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN);
+ /* second bit-flip (Universe/Local) is done according RFC2464 */
+ tmp.s6_addr[8] ^= 0x02;
+ /* context information are always used */
+ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+ if (ipv6_addr_equal(&tmp, ipaddr)) {
+ dam = LOWPAN_IPHC_DAM_11;
+ goto out;
+ }
+ break;
}
memset(&tmp, 0, sizeof(tmp));
@@ -813,28 +866,85 @@ out:
return dam;
}
-static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct in6_addr *ipaddr,
+static inline bool
+lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
+ const void *lladdr)
+{
+ const struct ieee802154_addr *addr = lladdr;
+ unsigned char extended_addr[EUI64_ADDR_LEN];
+ struct in6_addr tmp = {};
+ bool lladdr_compress = false;
+
+ switch (addr->mode) {
+ case IEEE802154_ADDR_LONG:
+ ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
+ if (is_addr_mac_addr_based(ipaddr, extended_addr))
+ lladdr_compress = true;
+ break;
+ case IEEE802154_ADDR_SHORT:
+ /* fe:80::ff:fe00:XXXX
+ * \__/
+ * short_addr
+ *
+ * Universe/Local bit is zero.
+ */
+ tmp.s6_addr[0] = 0xFE;
+ tmp.s6_addr[1] = 0x80;
+ tmp.s6_addr[11] = 0xFF;
+ tmp.s6_addr[12] = 0xFE;
+ ieee802154_le16_to_be16(&tmp.s6_addr16[7],
+ &addr->short_addr);
+ if (ipv6_addr_equal(&tmp, ipaddr))
+ lladdr_compress = true;
+ break;
+ default:
+ /* should never handled and filtered by 802154 6lowpan */
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ return lladdr_compress;
+}
+
+static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
+ const struct in6_addr *ipaddr,
const unsigned char *lladdr, bool sam)
{
- u8 dam = LOWPAN_IPHC_DAM_00;
+ u8 dam = LOWPAN_IPHC_DAM_01;
- if (is_addr_mac_addr_based(ipaddr, lladdr)) {
- dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
- pr_debug("address compression 0 bits\n");
- } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+ switch (lowpan_dev(dev)->lltype) {
+ case LOWPAN_LLTYPE_IEEE802154:
+ if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) {
+ dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
+ pr_debug("address compression 0 bits\n");
+ goto out;
+ }
+ break;
+ default:
+ if (is_addr_mac_addr_based(ipaddr, lladdr)) {
+ dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
+ pr_debug("address compression 0 bits\n");
+ goto out;
+ }
+ break;
+ }
+
+ if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
/* compress IID to 16 bits xxxx::XXXX */
lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
dam = LOWPAN_IPHC_DAM_10; /* 16-bits */
raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
*hc_ptr - 2, 2);
- } else {
- /* do not compress IID => xxxx::IID */
- lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
- dam = LOWPAN_IPHC_DAM_01; /* 64-bits */
- raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
- *hc_ptr - 8, 8);
+ goto out;
}
+ /* do not compress IID => xxxx::IID */
+ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
+ raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
+ *hc_ptr - 8, 8);
+
+out:
+
if (sam)
return lowpan_iphc_dam_to_sam_value[dam];
else
@@ -1013,9 +1123,6 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
iphc0 = LOWPAN_DISPATCH_IPHC;
iphc1 = 0;
- raw_dump_inline(__func__, "saddr", saddr, EUI64_ADDR_LEN);
- raw_dump_inline(__func__, "daddr", daddr, EUI64_ADDR_LEN);
-
raw_dump_table(__func__, "sending raw skb network uncompressed packet",
skb->data, skb->len);
@@ -1088,14 +1195,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
iphc1 |= LOWPAN_IPHC_SAC;
} else {
if (sci) {
- iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->saddr,
+ iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
+ &hdr->saddr,
&sci_entry, saddr,
true);
iphc1 |= LOWPAN_IPHC_SAC;
} else {
if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL &&
lowpan_is_linklocal_zero_padded(hdr->saddr)) {
- iphc1 |= lowpan_compress_addr_64(&hc_ptr,
+ iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
&hdr->saddr,
saddr, true);
pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
@@ -1123,14 +1231,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
}
} else {
if (dci) {
- iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->daddr,
+ iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
+ &hdr->daddr,
&dci_entry, daddr,
false);
iphc1 |= LOWPAN_IPHC_DAC;
} else {
if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL &&
lowpan_is_linklocal_zero_padded(hdr->daddr)) {
- iphc1 |= lowpan_compress_addr_64(&hc_ptr,
+ iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
&hdr->daddr,
daddr, false);
pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n",
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index e459afd..88c9d16 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -9,6 +9,7 @@
*/
#include <net/6lowpan.h>
+#include <net/ndisc.h>
#include <net/ieee802154_netdev.h>
#include <net/mac802154.h>
@@ -17,19 +18,9 @@
#define LOWPAN_FRAG1_HEAD_SIZE 0x4
#define LOWPAN_FRAGN_HEAD_SIZE 0x5
-/* don't save pan id, it's intra pan */
-struct lowpan_addr {
- u8 mode;
- union {
- /* IPv6 needs big endian here */
- __be64 extended_addr;
- __be16 short_addr;
- } u;
-};
-
struct lowpan_addr_info {
- struct lowpan_addr daddr;
- struct lowpan_addr saddr;
+ struct ieee802154_addr daddr;
+ struct ieee802154_addr saddr;
};
static inline struct
@@ -48,12 +39,14 @@ lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
* RAW/DGRAM sockets.
*/
int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
- unsigned short type, const void *_daddr,
- const void *_saddr, unsigned int len)
+ unsigned short type, const void *daddr,
+ const void *saddr, unsigned int len)
{
- const u8 *saddr = _saddr;
- const u8 *daddr = _daddr;
- struct lowpan_addr_info *info;
+ struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
+ struct lowpan_addr_info *info = lowpan_skb_priv(skb);
+ struct lowpan_802154_neigh *llneigh = NULL;
+ const struct ipv6hdr *hdr = ipv6_hdr(skb);
+ struct neighbour *n;
/* TODO:
* if this package isn't ipv6 one, where should it be routed?
@@ -61,21 +54,44 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
if (type != ETH_P_IPV6)
return 0;
- if (!saddr)
- saddr = ldev->dev_addr;
+ /* intra-pan communication */
+ info->saddr.pan_id = wpan_dev->pan_id;
+ info->daddr.pan_id = info->saddr.pan_id;
- raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
- raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
+ if (!memcmp(daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
+ info->daddr.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+ info->daddr.mode = IEEE802154_ADDR_SHORT;
+ } else {
+ n = neigh_lookup(&nd_tbl, &hdr->daddr, ldev);
+ if (n)
+ llneigh = lowpan_802154_neigh(neighbour_priv(n));
+
+ if (llneigh &&
+ ieee802154_is_valid_src_short_addr(llneigh->short_addr)) {
+ info->daddr.mode = IEEE802154_ADDR_SHORT;
+ info->daddr.short_addr = llneigh->short_addr;
+ } else {
+ info->daddr.mode = IEEE802154_ADDR_LONG;
+ ieee802154_be64_to_le64(&info->daddr.extended_addr,
+ daddr);
+ }
- info = lowpan_skb_priv(skb);
+ if (n)
+ neigh_release(n);
+ }
- /* TODO: Currently we only support extended_addr */
- info->daddr.mode = IEEE802154_ADDR_LONG;
- memcpy(&info->daddr.u.extended_addr, daddr,
- sizeof(info->daddr.u.extended_addr));
- info->saddr.mode = IEEE802154_ADDR_LONG;
- memcpy(&info->saddr.u.extended_addr, saddr,
- sizeof(info->daddr.u.extended_addr));
+ if (!saddr) {
+ if (ieee802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
+ info->saddr.mode = IEEE802154_ADDR_SHORT;
+ info->saddr.short_addr = wpan_dev->short_addr;
+ } else {
+ info->saddr.mode = IEEE802154_ADDR_LONG;
+ info->saddr.extended_addr = wpan_dev->extended_addr;
+ }
+ } else {
+ info->saddr.mode = IEEE802154_ADDR_LONG;
+ ieee802154_be64_to_le64(&info->saddr.extended_addr, saddr);
+ }
return 0;
}
@@ -209,47 +225,26 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
u16 *dgram_size, u16 *dgram_offset)
{
struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
- struct ieee802154_addr sa, da;
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
struct lowpan_addr_info info;
- void *daddr, *saddr;
memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
- /* TODO: Currently we only support extended_addr */
- daddr = &info.daddr.u.extended_addr;
- saddr = &info.saddr.u.extended_addr;
-
*dgram_size = skb->len;
- lowpan_header_compress(skb, ldev, daddr, saddr);
+ lowpan_header_compress(skb, ldev, &info.daddr, &info.saddr);
/* dgram_offset = (saved bytes after compression) + lowpan header len */
*dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);
cb->type = IEEE802154_FC_TYPE_DATA;
- /* prepare wpan address data */
- sa.mode = IEEE802154_ADDR_LONG;
- sa.pan_id = wpan_dev->pan_id;
- sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
-
- /* intra-PAN communications */
- da.pan_id = sa.pan_id;
-
- /* if the destination address is the broadcast address, use the
- * corresponding short address
- */
- if (!memcmp(daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
- da.mode = IEEE802154_ADDR_SHORT;
- da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+ if (info.daddr.mode == IEEE802154_ADDR_SHORT &&
+ ieee802154_is_broadcast_short_addr(info.daddr.short_addr))
cb->ackreq = false;
- } else {
- da.mode = IEEE802154_ADDR_LONG;
- da.extended_addr = ieee802154_devaddr_from_raw(daddr);
+ else
cb->ackreq = wpan_dev->ackreq;
- }
- return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev, &da,
- &sa, 0);
+ return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev,
+ &info.daddr, &info.saddr, 0);
}
netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
--
2.8.0
^ permalink raw reply related
* Re: [PATCH] macsec: fix crypto Kconfig dependency
From: Arnd Bergmann @ 2016-04-18 11:07 UTC (permalink / raw)
To: Herbert Xu; +Cc: davem, sd, hannes, johannes, netdev, linux-kernel
In-Reply-To: <20160418104336.GA19175@gondor.apana.org.au>
On Monday 18 April 2016 18:43:36 Herbert Xu wrote:
>
> It's kind of silly really now that IPv4 selects CRYPTO which
> means that you can't really avoid seeing all those options which
> most users won't care about.
I had not noticed that IPv4 does it, but that is a good point.
We have had a couple of other subsystems with the issue (e.g. MFD),
and have turned around the logic in the end so the user-visible
options are always there and the subsystem core is selected by
all drivers that need it. We could do the same for crypto as below
(untested). I only select CRYPTO from ALGAPI2 there, which may be
wrong if some parts of crypto need the core but do not need algapi,
but it illustrates what we could do.
Arnd
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 93a1fdc1feee..ed1bc0c49022 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -12,14 +12,12 @@ source "crypto/async_tx/Kconfig"
#
# Cryptographic API Configuration
#
-menuconfig CRYPTO
- tristate "Cryptographic API"
+config CRYPTO
+ tristate
help
This option provides the core Cryptographic API.
-if CRYPTO
-
-comment "Crypto core or helper"
+menu "Crypto core or helper"
config CRYPTO_FIPS
bool "FIPS 200 compliance"
@@ -39,6 +37,7 @@ config CRYPTO_ALGAPI
config CRYPTO_ALGAPI2
tristate
+ select CRYPTO
config CRYPTO_AEAD
tristate
@@ -1633,4 +1632,4 @@ source "drivers/crypto/Kconfig"
source crypto/asymmetric_keys/Kconfig
source certs/Kconfig
-endif # if CRYPTO
+endmenu
^ permalink raw reply related
* [PATCH v2 2/4] io-mapping: Specify mapping size for io_mapping_map_wc()
From: Chris Wilson @ 2016-04-18 11:14 UTC (permalink / raw)
To: intel-gfx
Cc: Tvrtko Ursulin, netdev, Yishai Hadas, linux-kernel,
Peter Zijlstra (Intel), dri-devel, linux-rdma, Daniel Vetter,
Dan Williams, Ingo Molnar, David Hildenbrand
In-Reply-To: <1460978042-9953-1-git-send-email-chris@chris-wilson.co.uk>
The ioremap() hidden behind the io_mapping_map_wc() convenience helper
can be used for remapping multiple pages. Extend the helper so that
future callers can use it for larger ranges.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: David Airlie <airlied@linux.ie>
Cc: Yishai Hadas <yishaih@mellanox.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>
Cc: David Hildenbrand <dahi@linux.vnet.ibm.com>
Cc: intel-gfx@lists.freedesktop.org
Cc: dri-devel@lists.freedesktop.org
Cc: netdev@vger.kernel.org
Cc: linux-rdma@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
drivers/gpu/drm/i915/intel_overlay.c | 3 ++-
drivers/net/ethernet/mellanox/mlx4/pd.c | 4 +++-
include/linux/io-mapping.h | 10 +++++++---
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 9746b9841c13..0d5a376878d3 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -198,7 +198,8 @@ intel_overlay_map_regs(struct intel_overlay *overlay)
regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_handle->vaddr;
else
regs = io_mapping_map_wc(ggtt->mappable,
- overlay->flip_addr);
+ overlay->flip_addr,
+ PAGE_SIZE);
return regs;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c
index b3cc3ab63799..6fc156a3918d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/pd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/pd.c
@@ -205,7 +205,9 @@ int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node)
goto free_uar;
}
- uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT);
+ uar->bf_map = io_mapping_map_wc(priv->bf_mapping,
+ uar->index << PAGE_SHIFT,
+ PAGE_SIZE);
if (!uar->bf_map) {
err = -ENOMEM;
goto unamp_uar;
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index e399029b68c5..645ad06b5d52 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -100,14 +100,16 @@ io_mapping_unmap_atomic(void __iomem *vaddr)
}
static inline void __iomem *
-io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
+io_mapping_map_wc(struct io_mapping *mapping,
+ unsigned long offset,
+ unsigned long size)
{
resource_size_t phys_addr;
BUG_ON(offset >= mapping->size);
phys_addr = mapping->base + offset;
- return ioremap_wc(phys_addr, PAGE_SIZE);
+ return ioremap_wc(phys_addr, size);
}
static inline void
@@ -155,7 +157,9 @@ io_mapping_unmap_atomic(void __iomem *vaddr)
/* Non-atomic map/unmap */
static inline void __iomem *
-io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
+io_mapping_map_wc(struct io_mapping *mapping,
+ unsigned long offset,
+ unsigned long size)
{
return ((char __force __iomem *) mapping) + offset;
}
--
2.8.0.rc3
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH] net/mlx4_en: allocate non 0-order pages for RX ring with __GFP_NOMEMALLOC
From: Konstantin Khlebnikov @ 2016-04-18 11:33 UTC (permalink / raw)
To: netdev, Yishai Hadas, Eugenia Emantayev; +Cc: linux-kernel
High order pages are optional here since commit 51151a16a60f ("mlx4: allow
order-0 memory allocations in RX path"), so here is no reason for depleting
reserves. Generic __netdev_alloc_frag() implements the same logic.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 86bcfe510e4e..56d070d9cf01 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -61,7 +61,7 @@ static int mlx4_alloc_pages(struct mlx4_en_priv *priv,
gfp_t gfp = _gfp;
if (order)
- gfp |= __GFP_COMP | __GFP_NOWARN;
+ gfp |= __GFP_COMP | __GFP_NOWARN | __GFP_NOMEMALLOC;
page = alloc_pages(gfp, order);
if (likely(page))
break;
^ permalink raw reply related
* [PATCH] net/mlx4_en: do batched put_page using atomic_sub
From: Konstantin Khlebnikov @ 2016-04-18 11:34 UTC (permalink / raw)
To: netdev, Yishai Hadas, Eugenia Emantayev; +Cc: linux-kernel
This patch fixes couple error paths after allocation failures.
Atomic set of page reference counter is safe only if it is zero,
otherwise set can race with any speculative get_page_unless_zero.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 56d070d9cf01..7d25bc9c1b22 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -126,7 +126,9 @@ out:
dma_unmap_page(priv->ddev, page_alloc[i].dma,
page_alloc[i].page_size, PCI_DMA_FROMDEVICE);
page = page_alloc[i].page;
- set_page_count(page, 1);
+ /* Revert changes done by mlx4_alloc_pages */
+ page_ref_sub(page, page_alloc[i].page_size /
+ priv->frag_info[i].frag_stride - 1);
put_page(page);
}
}
@@ -176,7 +178,9 @@ out:
dma_unmap_page(priv->ddev, page_alloc->dma,
page_alloc->page_size, PCI_DMA_FROMDEVICE);
page = page_alloc->page;
- set_page_count(page, 1);
+ /* Revert changes done by mlx4_alloc_pages */
+ page_ref_sub(page, page_alloc->page_size /
+ priv->frag_info[i].frag_stride - 1);
put_page(page);
page_alloc->page = NULL;
}
^ permalink raw reply related
* [PATCH] cls_cgroup: get sk_classid only from full sockets
From: Konstantin Khlebnikov @ 2016-04-18 11:37 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: cgroups, linux-kernel
skb->sk could point to timewait or request socket which has no sk_classid.
Detected as "BUG: KASAN: slab-out-of-bounds in cls_cgroup_classify".
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
include/net/cls_cgroup.h | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
index c0a92e2c286d..74c9693d4941 100644
--- a/include/net/cls_cgroup.h
+++ b/include/net/cls_cgroup.h
@@ -17,6 +17,7 @@
#include <linux/hardirq.h>
#include <linux/rcupdate.h>
#include <net/sock.h>
+#include <net/inet_sock.h>
#ifdef CONFIG_CGROUP_NET_CLASSID
struct cgroup_cls_state {
@@ -63,11 +64,13 @@ static inline u32 task_get_classid(const struct sk_buff *skb)
* softirqs always disables bh.
*/
if (in_serving_softirq()) {
+ struct sock *sk = skb_to_full_sk(skb);
+
/* If there is an sock_cgroup_classid we'll use that. */
- if (!skb->sk)
+ if (!sk || !sk_fullsock(sk))
return 0;
- classid = sock_cgroup_classid(&skb->sk->sk_cgrp_data);
+ classid = sock_cgroup_classid(&sk->sk_cgrp_data);
}
return classid;
^ permalink raw reply related
* [PATCH 1/2] net/ipv6/addrconf: simplify sysctl registration
From: Konstantin Khlebnikov @ 2016-04-18 11:41 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: linux-kernel
Struct ctl_table_header holds pointer to sysctl table which could be used
for freeing it after unregistration. IPv4 sysctls already use that.
Remove redundant NULL assignment: ndev allocated using kzalloc.
This also saves some bytes: sysctl table could be shorter than
DEVCONF_MAX+1 if some options are disable in config.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
include/linux/ipv6.h | 3 ++-
net/ipv6/addrconf.c | 43 +++++++++++++++++--------------------------
2 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 7edc14fb66b6..58d6e158755f 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -63,7 +63,8 @@ struct ipv6_devconf {
} stable_secret;
__s32 use_oif_addrs_only;
__s32 keep_addr_on_down;
- void *sysctl;
+
+ struct ctl_table_header *sysctl_header;
};
struct ipv6_params {
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 27aed1afcf81..8a724c7136b0 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -359,7 +359,6 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64;
ndev->cnf.mtu6 = dev->mtu;
- ndev->cnf.sysctl = NULL;
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
if (!ndev->nd_parms) {
kfree(ndev);
@@ -5618,13 +5617,7 @@ int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl,
return ret;
}
-static struct addrconf_sysctl_table
-{
- struct ctl_table_header *sysctl_header;
- struct ctl_table addrconf_vars[DEVCONF_MAX+1];
-} addrconf_sysctl __read_mostly = {
- .sysctl_header = NULL,
- .addrconf_vars = {
+static const struct ctl_table addrconf_sysctl[] = {
{
.procname = "forwarding",
.data = &ipv6_devconf.forwarding,
@@ -5942,52 +5935,50 @@ static struct addrconf_sysctl_table
{
/* sentinel */
}
- },
};
static int __addrconf_sysctl_register(struct net *net, char *dev_name,
struct inet6_dev *idev, struct ipv6_devconf *p)
{
int i;
- struct addrconf_sysctl_table *t;
+ struct ctl_table *table;
char path[sizeof("net/ipv6/conf/") + IFNAMSIZ];
- t = kmemdup(&addrconf_sysctl, sizeof(*t), GFP_KERNEL);
- if (!t)
+ table = kmemdup(addrconf_sysctl, sizeof(addrconf_sysctl), GFP_KERNEL);
+ if (!table)
goto out;
- for (i = 0; t->addrconf_vars[i].data; i++) {
- t->addrconf_vars[i].data += (char *)p - (char *)&ipv6_devconf;
- t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
- t->addrconf_vars[i].extra2 = net;
+ for (i = 0; table[i].data; i++) {
+ table[i].data += (char *)p - (char *)&ipv6_devconf;
+ table[i].extra1 = idev; /* embedded; no ref */
+ table[i].extra2 = net;
}
snprintf(path, sizeof(path), "net/ipv6/conf/%s", dev_name);
- t->sysctl_header = register_net_sysctl(net, path, t->addrconf_vars);
- if (!t->sysctl_header)
+ p->sysctl_header = register_net_sysctl(net, path, table);
+ if (!p->sysctl_header)
goto free;
- p->sysctl = t;
return 0;
free:
- kfree(t);
+ kfree(table);
out:
return -ENOBUFS;
}
static void __addrconf_sysctl_unregister(struct ipv6_devconf *p)
{
- struct addrconf_sysctl_table *t;
+ struct ctl_table *table;
- if (!p->sysctl)
+ if (!p->sysctl_header)
return;
- t = p->sysctl;
- p->sysctl = NULL;
- unregister_net_sysctl_table(t->sysctl_header);
- kfree(t);
+ table = p->sysctl_header->ctl_table_arg;
+ unregister_net_sysctl_table(p->sysctl_header);
+ p->sysctl_header = NULL;
+ kfree(table);
}
static int addrconf_sysctl_register(struct inet6_dev *idev)
^ permalink raw reply related
* [PATCH 2/2] net/ipv6/addrconf: fix sysctl table indentation
From: Konstantin Khlebnikov @ 2016-04-18 11:41 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: linux-kernel
In-Reply-To: <146097967035.15409.8235893232862124602.stgit@buzz>
Separated from previous patch for readability.
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
---
net/ipv6/addrconf.c | 616 +++++++++++++++++++++++++--------------------------
1 file changed, 307 insertions(+), 309 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8a724c7136b0..51574ba5d328 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5618,323 +5618,321 @@ int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl,
}
static const struct ctl_table addrconf_sysctl[] = {
- {
- .procname = "forwarding",
- .data = &ipv6_devconf.forwarding,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_forward,
- },
- {
- .procname = "hop_limit",
- .data = &ipv6_devconf.hop_limit,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_hop_limit,
- },
- {
- .procname = "mtu",
- .data = &ipv6_devconf.mtu6,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_mtu,
- },
- {
- .procname = "accept_ra",
- .data = &ipv6_devconf.accept_ra,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "accept_redirects",
- .data = &ipv6_devconf.accept_redirects,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "autoconf",
- .data = &ipv6_devconf.autoconf,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "dad_transmits",
- .data = &ipv6_devconf.dad_transmits,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "router_solicitations",
- .data = &ipv6_devconf.rtr_solicits,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "router_solicitation_interval",
- .data = &ipv6_devconf.rtr_solicit_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
- .procname = "router_solicitation_delay",
- .data = &ipv6_devconf.rtr_solicit_delay,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
- .procname = "force_mld_version",
- .data = &ipv6_devconf.force_mld_version,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "mldv1_unsolicited_report_interval",
- .data =
- &ipv6_devconf.mldv1_unsolicited_report_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_ms_jiffies,
- },
- {
- .procname = "mldv2_unsolicited_report_interval",
- .data =
- &ipv6_devconf.mldv2_unsolicited_report_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_ms_jiffies,
- },
- {
- .procname = "use_tempaddr",
- .data = &ipv6_devconf.use_tempaddr,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "temp_valid_lft",
- .data = &ipv6_devconf.temp_valid_lft,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "temp_prefered_lft",
- .data = &ipv6_devconf.temp_prefered_lft,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "regen_max_retry",
- .data = &ipv6_devconf.regen_max_retry,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "max_desync_factor",
- .data = &ipv6_devconf.max_desync_factor,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "max_addresses",
- .data = &ipv6_devconf.max_addresses,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "accept_ra_defrtr",
- .data = &ipv6_devconf.accept_ra_defrtr,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "accept_ra_min_hop_limit",
- .data = &ipv6_devconf.accept_ra_min_hop_limit,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "accept_ra_pinfo",
- .data = &ipv6_devconf.accept_ra_pinfo,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
+ {
+ .procname = "forwarding",
+ .data = &ipv6_devconf.forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_forward,
+ },
+ {
+ .procname = "hop_limit",
+ .data = &ipv6_devconf.hop_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_hop_limit,
+ },
+ {
+ .procname = "mtu",
+ .data = &ipv6_devconf.mtu6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_mtu,
+ },
+ {
+ .procname = "accept_ra",
+ .data = &ipv6_devconf.accept_ra,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "accept_redirects",
+ .data = &ipv6_devconf.accept_redirects,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "autoconf",
+ .data = &ipv6_devconf.autoconf,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "dad_transmits",
+ .data = &ipv6_devconf.dad_transmits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "router_solicitations",
+ .data = &ipv6_devconf.rtr_solicits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "router_solicitation_interval",
+ .data = &ipv6_devconf.rtr_solicit_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
+ },
+ {
+ .procname = "router_solicitation_delay",
+ .data = &ipv6_devconf.rtr_solicit_delay,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
+ },
+ {
+ .procname = "force_mld_version",
+ .data = &ipv6_devconf.force_mld_version,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "mldv1_unsolicited_report_interval",
+ .data =
+ &ipv6_devconf.mldv1_unsolicited_report_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_ms_jiffies,
+ },
+ {
+ .procname = "mldv2_unsolicited_report_interval",
+ .data =
+ &ipv6_devconf.mldv2_unsolicited_report_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_ms_jiffies,
+ },
+ {
+ .procname = "use_tempaddr",
+ .data = &ipv6_devconf.use_tempaddr,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "temp_valid_lft",
+ .data = &ipv6_devconf.temp_valid_lft,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "temp_prefered_lft",
+ .data = &ipv6_devconf.temp_prefered_lft,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "regen_max_retry",
+ .data = &ipv6_devconf.regen_max_retry,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "max_desync_factor",
+ .data = &ipv6_devconf.max_desync_factor,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "max_addresses",
+ .data = &ipv6_devconf.max_addresses,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "accept_ra_defrtr",
+ .data = &ipv6_devconf.accept_ra_defrtr,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "accept_ra_min_hop_limit",
+ .data = &ipv6_devconf.accept_ra_min_hop_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "accept_ra_pinfo",
+ .data = &ipv6_devconf.accept_ra_pinfo,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#ifdef CONFIG_IPV6_ROUTER_PREF
- {
- .procname = "accept_ra_rtr_pref",
- .data = &ipv6_devconf.accept_ra_rtr_pref,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "router_probe_interval",
- .data = &ipv6_devconf.rtr_probe_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
+ {
+ .procname = "accept_ra_rtr_pref",
+ .data = &ipv6_devconf.accept_ra_rtr_pref,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "router_probe_interval",
+ .data = &ipv6_devconf.rtr_probe_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
+ },
#ifdef CONFIG_IPV6_ROUTE_INFO
- {
- .procname = "accept_ra_rt_info_max_plen",
- .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
+ {
+ .procname = "accept_ra_rt_info_max_plen",
+ .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#endif
#endif
- {
- .procname = "proxy_ndp",
- .data = &ipv6_devconf.proxy_ndp,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_proxy_ndp,
- },
- {
- .procname = "accept_source_route",
- .data = &ipv6_devconf.accept_source_route,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
+ {
+ .procname = "proxy_ndp",
+ .data = &ipv6_devconf.proxy_ndp,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_proxy_ndp,
+ },
+ {
+ .procname = "accept_source_route",
+ .data = &ipv6_devconf.accept_source_route,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
- {
- .procname = "optimistic_dad",
- .data = &ipv6_devconf.optimistic_dad,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
-
- },
- {
- .procname = "use_optimistic",
- .data = &ipv6_devconf.use_optimistic,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
-
- },
+ {
+ .procname = "optimistic_dad",
+ .data = &ipv6_devconf.optimistic_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "use_optimistic",
+ .data = &ipv6_devconf.use_optimistic,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
#endif
#ifdef CONFIG_IPV6_MROUTE
- {
- .procname = "mc_forwarding",
- .data = &ipv6_devconf.mc_forwarding,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = proc_dointvec,
- },
+ {
+ .procname = "mc_forwarding",
+ .data = &ipv6_devconf.mc_forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ },
#endif
- {
- .procname = "disable_ipv6",
- .data = &ipv6_devconf.disable_ipv6,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_disable,
- },
- {
- .procname = "accept_dad",
- .data = &ipv6_devconf.accept_dad,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "force_tllao",
- .data = &ipv6_devconf.force_tllao,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
- .procname = "ndisc_notify",
- .data = &ipv6_devconf.ndisc_notify,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
- .procname = "suppress_frag_ndisc",
- .data = &ipv6_devconf.suppress_frag_ndisc,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
- .procname = "accept_ra_from_local",
- .data = &ipv6_devconf.accept_ra_from_local,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "accept_ra_mtu",
- .data = &ipv6_devconf.accept_ra_mtu,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "stable_secret",
- .data = &ipv6_devconf.stable_secret,
- .maxlen = IPV6_MAX_STRLEN,
- .mode = 0600,
- .proc_handler = addrconf_sysctl_stable_secret,
- },
- {
- .procname = "use_oif_addrs_only",
- .data = &ipv6_devconf.use_oif_addrs_only,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "ignore_routes_with_linkdown",
- .data = &ipv6_devconf.ignore_routes_with_linkdown,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_ignore_routes_with_linkdown,
- },
- {
- .procname = "drop_unicast_in_l2_multicast",
- .data = &ipv6_devconf.drop_unicast_in_l2_multicast,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "drop_unsolicited_na",
- .data = &ipv6_devconf.drop_unsolicited_na,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "keep_addr_on_down",
- .data = &ipv6_devconf.keep_addr_on_down,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
-
- },
- {
- /* sentinel */
- }
+ {
+ .procname = "disable_ipv6",
+ .data = &ipv6_devconf.disable_ipv6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_disable,
+ },
+ {
+ .procname = "accept_dad",
+ .data = &ipv6_devconf.accept_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "force_tllao",
+ .data = &ipv6_devconf.force_tllao,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .procname = "ndisc_notify",
+ .data = &ipv6_devconf.ndisc_notify,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .procname = "suppress_frag_ndisc",
+ .data = &ipv6_devconf.suppress_frag_ndisc,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .procname = "accept_ra_from_local",
+ .data = &ipv6_devconf.accept_ra_from_local,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "accept_ra_mtu",
+ .data = &ipv6_devconf.accept_ra_mtu,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "stable_secret",
+ .data = &ipv6_devconf.stable_secret,
+ .maxlen = IPV6_MAX_STRLEN,
+ .mode = 0600,
+ .proc_handler = addrconf_sysctl_stable_secret,
+ },
+ {
+ .procname = "use_oif_addrs_only",
+ .data = &ipv6_devconf.use_oif_addrs_only,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "ignore_routes_with_linkdown",
+ .data = &ipv6_devconf.ignore_routes_with_linkdown,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_ignore_routes_with_linkdown,
+ },
+ {
+ .procname = "drop_unicast_in_l2_multicast",
+ .data = &ipv6_devconf.drop_unicast_in_l2_multicast,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "drop_unsolicited_na",
+ .data = &ipv6_devconf.drop_unsolicited_na,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .procname = "keep_addr_on_down",
+ .data = &ipv6_devconf.keep_addr_on_down,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+
+ },
+ {
+ /* sentinel */
+ }
};
static int __addrconf_sysctl_register(struct net *net, char *dev_name,
^ permalink raw reply related
* RE: Poorer networking performance in later kernels?
From: Butler, Peter @ 2016-04-18 11:27 UTC (permalink / raw)
To: Rick Jones, netdev@vger.kernel.org
In-Reply-To: <57116D21.8000807@hpe.com>
Hi Rick
Thanks for the reply.
Here is some hardware information, as requested (the two systems are identical, and are communicating with one another over a 10GB full-duplex Ethernet backplane):
- processor type: Intel(R) Xeon(R) CPU C5528 @ 2.13GHz
- NIC: Intel 82599EB 10GB XAUI/BX4
- NIC driver: ixgbe version 4.2.1-k (part of 4.4.0 kernel)
As for the buffer sizes, those rather large ones work fine for us with the 3.4.2 kernel. However, for the sake of being complete, I have re-tried the tests with the 'standard' 4.4.0 kernel parameters for all /proc/sys/net/* values, and the results still were extremely poor in comparison to the 3.4.2 kernel.
Our MTU is actually just the standard 1500 bytes, however the message size was chosen to mimic actual traffic which will be segmented.
I ran ethtool -k (indeed I checked all ethtool parameters, not just those via -k) and the only real difference I could find was in "large-receive-offload" which was ON in 3.4.2 but OFF in 4.4.0 - so I used ethtool to change this to match the 3.4.2 settings and re-ran the tests. Didn't help :-( It's possible of course that I have missed a parameter here or there in comparing the 3.4.2 setup to the 4.4.0 setup. I also tried running the ethtool config with the latest and greatest ethtool version (4.5) on the 4.4.0 kernel, as compared to the old 3.1 version on our 3.4.2 kernel.
I performed the TCP_RR test as requested and in that case, the results are much more comparable. The old kernel is still better, but now only around 10% better as opposed to 2-3x better.
However I still contend that the *_STREAM tests are giving us more pertinent data, since our product application is only getting 1/3 to 1/2 half of the performance on the 4.4.0 kernel, and this is the same thing I see when I use netperf to test.
One other note: I tried running our 3.4.2 and 4.4.0 kernels in a VM environment on my workstation, so as to take the 'real' production hardware out of the equation. When I perform the tests in this setup the 3.4.2 and 4.4.0 kernels perform identically - just as you would expect.
Any other ideas? What can I be missing here?
Peter
-----Original Message-----
From: Rick Jones [mailto:rick.jones2@hpe.com]
Sent: April-15-16 6:37 PM
To: Butler, Peter <pbutler@sonusnet.com>; netdev@vger.kernel.org
Subject: Re: Poorer networking performance in later kernels?
On 04/15/2016 02:02 PM, Butler, Peter wrote:
> (Please keep me CC'd to all comments/responses)
>
> I've tried a kernel upgrade from 3.4.2 to 4.4.0 and see a marked drop
> in networking performance. Nothing was changed on the test systems,
> other than the kernel itself (and kernel modules). The identical
> .config used to build the 3.4.2 kernel was brought over into the
> 4.4.0 kernel source tree, and any configuration differences (e.g. new
> parameters, etc.) were taken as default values.
>
> The testing was performed on the same actual hardware for both kernel
> versions (i.e. take the existing 3.4.2 physical setup, simply boot
> into the (new) kernel and run the same test). The netperf utility was
> used for benchmarking and the testing was always performed on idle
> systems.
>
> TCP testing yielded the following results, where the 4.4.0 kernel only
> got about 1/2 of the throughput:
>
> Recv Send Send Utilization Service Demand
> Socket Socket Message Elapsed Send Recv Send Recv
> Size Size Size Time Throughput local remote local remote
> bytes bytes bytes secs. 10^6bits/s % S % S us/KB us/KB
>
> 3.4.2 13631488 13631488 8952 30.01 9370.29 10.14 6.50 0.709 0.454
> 4.4.0 13631488 13631488 8952 30.02 5314.03 9.14 14.31 1.127 1.765
>
> SCTP testing yielded the following results, where the 4.4.0 kernel only got about 1/3 of the throughput:
>
> Recv Send Send Utilization Service Demand
> Socket Socket Message Elapsed Send Recv Send Recv
> Size Size Size Time Throughput local remote local remote
> bytes bytes bytes secs. 10^6bits/s % S % S us/KB us/KB
>
> 3.4.2 13631488 13631488 8952 30.00 2306.22 13.87 13.19 3.941 3.747
> 4.4.0 13631488 13631488 8952 30.01 882.74 16.86 19.14 12.516 14.210
>
> The same tests were performed a multitude of time, and are always
> consistent (within a few percent). I've also tried playing with
> various run-time kernel parameters (/proc/sys/kernel/net/...) on the
> 4.4.0 kernel to alleviate the issue but have had no success at all.
>
> I'm at a loss as to what could possibly account for such a discrepancy...
>
I suspect I am not alone in being curious about the CPU(s) present in the systems and the model/whatnot of the NIC being used. I'm also curious as to why you have what at first glance seem like absurdly large socket buffer sizes.
That said, it looks like you have some Really Big (tm) increases in service demand. Many more CPU cycles being consumed per KB of data transferred.
Your message size makes me wonder if you were using a 9000 byte MTU.
Perhaps in the move from 3.4.2 to 4.4.0 you lost some or all of the stateless offloads for your NIC(s)? Running ethtool -k <interface> on both ends under both kernels might be good.
Also, if you did have a 9000 byte MTU under 3.4.2 are you certain you still had it under 4.4.0?
It would (at least to me) also be interesting to run a TCP_RR test comparing the two kernels. TCP_RR (at least with the default request/response size of one byte) doesn't really care about stateless offloads or MTUs and could show how much difference there is in basic path length (or I suppose in interrupt coalescing behaviour if the NIC in question has a mildly dodgy heuristic for such things).
happy benchmarking,
rick jones
^ permalink raw reply
* Re: [PATCH] net/mlx4_en: allocate non 0-order pages for RX ring with __GFP_NOMEMALLOC
From: Eric Dumazet @ 2016-04-18 12:12 UTC (permalink / raw)
To: Konstantin Khlebnikov
Cc: netdev, Yishai Hadas, Eugenia Emantayev, linux-kernel
In-Reply-To: <146097923460.15114.8965134124148581055.stgit@buzz>
On Mon, 2016-04-18 at 14:33 +0300, Konstantin Khlebnikov wrote:
> High order pages are optional here since commit 51151a16a60f ("mlx4: allow
> order-0 memory allocations in RX path"), so here is no reason for depleting
> reserves. Generic __netdev_alloc_frag() implements the same logic.
>
> Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
> ---
> drivers/net/ethernet/mellanox/mlx4/en_rx.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Acked-by: Eric Dumazet <edumazet@google.com>
Thanks !
^ permalink raw reply
* Re: [PATCH V2] net: ethernet: mellanox: correct page conversion
From: Christoph Hellwig @ 2016-04-18 12:12 UTC (permalink / raw)
To: Sinan Kaya
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, timur-sgV2jX0FEOL9JmXXK+q4OQ,
cov-sgV2jX0FEOL9JmXXK+q4OQ, Yishai Hadas,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1460845412-13120-1-git-send-email-okaya-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On Sat, Apr 16, 2016 at 06:23:32PM -0400, Sinan Kaya wrote:
> Current code is assuming that the address returned by dma_alloc_coherent
> is a logical address. This is not true on ARM/ARM64 systems.
Can you explain what you mean with a 'logical address' and what actual
issue you're trying to solve?
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] cls_cgroup: get sk_classid only from full sockets
From: Eric Dumazet @ 2016-04-18 12:14 UTC (permalink / raw)
To: Konstantin Khlebnikov; +Cc: netdev, David S. Miller, cgroups, linux-kernel
In-Reply-To: <146097943086.15300.8997345346172526153.stgit@buzz>
On Mon, 2016-04-18 at 14:37 +0300, Konstantin Khlebnikov wrote:
> skb->sk could point to timewait or request socket which has no sk_classid.
> Detected as "BUG: KASAN: slab-out-of-bounds in cls_cgroup_classify".
>
> Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
> ---
Acked-by: Eric Dumazet <edumazet@google.com>
Thanks !
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox