* [PATCH 2/7] netlink: make validation_data const
From: Johannes Berg @ 2018-09-19 12:08 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
The validation data is only used within the policy that
should usually already be const, and isn't changed in any
code that uses it. Therefore, make the validation_data
pointer const.
While at it, remove the duplicate variable in the bitfield
validation that I'd otherwise have to change to const.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/netlink.h | 2 +-
lib/nlattr.c | 5 ++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/include/net/netlink.h b/include/net/netlink.h
index b680fe365e91..0d698215d4d9 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -237,7 +237,7 @@ enum {
struct nla_policy {
u16 type;
u16 len;
- void *validation_data;
+ const void *validation_data;
};
#define NLA_POLICY_EXACT_LEN(_len) { .type = NLA_EXACT_LEN, .len = _len }
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 120ad569e13d..e2e5b38394d5 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -45,12 +45,11 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
};
static int validate_nla_bitfield32(const struct nlattr *nla,
- u32 *valid_flags_allowed)
+ const u32 *valid_flags_mask)
{
const struct nla_bitfield32 *bf = nla_data(nla);
- u32 *valid_flags_mask = valid_flags_allowed;
- if (!valid_flags_allowed)
+ if (!valid_flags_mask)
return -EINVAL;
/*disallow invalid bit selector */
--
2.14.4
^ permalink raw reply related
* [PATCH 1/7] netlink: remove NLA_NESTED_COMPAT
From: Johannes Berg @ 2018-09-19 12:08 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
This isn't used anywhere, so we might as well get rid of it.
Reviewed-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/netlink.h | 2 --
lib/nlattr.c | 11 -----------
2 files changed, 13 deletions(-)
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 318b1ded3833..b680fe365e91 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -172,7 +172,6 @@ enum {
NLA_FLAG,
NLA_MSECS,
NLA_NESTED,
- NLA_NESTED_COMPAT,
NLA_NUL_STRING,
NLA_BINARY,
NLA_S8,
@@ -203,7 +202,6 @@ enum {
* NLA_BINARY Maximum length of attribute payload
* NLA_NESTED Don't use `len' field -- length verification is
* done by checking len of nested header (or empty)
- * NLA_NESTED_COMPAT Minimum length of structure payload
* NLA_U8, NLA_U16,
* NLA_U32, NLA_U64,
* NLA_S8, NLA_S16,
diff --git a/lib/nlattr.c b/lib/nlattr.c
index bb6fe5ed4ecf..120ad569e13d 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -140,17 +140,6 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
return -ERANGE;
break;
- case NLA_NESTED_COMPAT:
- if (attrlen < pt->len)
- return -ERANGE;
- if (attrlen < NLA_ALIGN(pt->len))
- break;
- if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN)
- return -ERANGE;
- nla = nla_data(nla) + NLA_ALIGN(pt->len);
- if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla))
- return -ERANGE;
- break;
case NLA_NESTED:
/* a nested attributes is allowed to be empty; if its not,
* it must have a size of at least NLA_HDRLEN.
--
2.14.4
^ permalink raw reply related
* [PATCH 4/7] netlink: combine validate/parse functions
From: Johannes Berg @ 2018-09-19 12:08 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
The parse function of course contains validate, but it's
implemented a second time, sharing just the validation
of a single attribute.
Introduce nla_validate_parse() that can be used for both
parsing/validation and only validation, to share code.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
lib/nlattr.c | 76 +++++++++++++++++++++++++++++++-----------------------------
1 file changed, 39 insertions(+), 37 deletions(-)
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 33404745bec4..966cd3dcf31b 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -158,6 +158,37 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
return 0;
}
+static int nla_validate_parse(const struct nlattr *head, int len, int maxtype,
+ const struct nla_policy *policy,
+ struct netlink_ext_ack *extack,
+ struct nlattr **tb)
+{
+ const struct nlattr *nla;
+ int rem;
+
+ nla_for_each_attr(nla, head, len, rem) {
+ static const char _msg[] = "Attribute failed policy validation";
+ const char *msg = _msg;
+ u16 type = nla_type(nla);
+
+ if (policy) {
+ int err = validate_nla(nla, maxtype, policy, &msg);
+
+ if (err < 0) {
+ if (extack)
+ extack->_msg = msg;
+ NL_SET_BAD_ATTR(extack, nla);
+ return err;
+ }
+ }
+
+ if (tb && type > 0 && type <= maxtype)
+ tb[type] = (struct nlattr *)nla;
+ }
+
+ return rem;
+}
+
/**
* nla_validate - Validate a stream of attributes
* @head: head of attribute stream
@@ -176,21 +207,12 @@ int nla_validate(const struct nlattr *head, int len, int maxtype,
const struct nla_policy *policy,
struct netlink_ext_ack *extack)
{
- const struct nlattr *nla;
int rem;
- nla_for_each_attr(nla, head, len, rem) {
- static const char _msg[] = "Attribute failed policy validation";
- const char *msg = _msg;
- int err = validate_nla(nla, maxtype, policy, &msg);
+ rem = nla_validate_parse(head, len, maxtype, policy, extack, NULL);
- if (err < 0) {
- if (extack)
- extack->_msg = msg;
- NL_SET_BAD_ATTR(extack, nla);
- return err;
- }
- }
+ if (rem < 0)
+ return rem;
return 0;
}
@@ -244,39 +266,19 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
int len, const struct nla_policy *policy,
struct netlink_ext_ack *extack)
{
- const struct nlattr *nla;
- int rem, err;
+ int rem;
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
- nla_for_each_attr(nla, head, len, rem) {
- u16 type = nla_type(nla);
-
- if (type > 0 && type <= maxtype) {
- static const char _msg[] = "Attribute failed policy validation";
- const char *msg = _msg;
-
- if (policy) {
- err = validate_nla(nla, maxtype, policy, &msg);
- if (err < 0) {
- NL_SET_BAD_ATTR(extack, nla);
- if (extack)
- extack->_msg = msg;
- goto errout;
- }
- }
-
- tb[type] = (struct nlattr *)nla;
- }
- }
+ rem = nla_validate_parse(head, len, maxtype, policy, extack, tb);
+ if (rem < 0)
+ return rem;
if (unlikely(rem > 0))
pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
rem, current->comm);
- err = 0;
-errout:
- return err;
+ return 0;
}
EXPORT_SYMBOL(nla_parse);
--
2.14.4
^ permalink raw reply related
* [PATCH 3/7] netlink: set extack error message in nla_validate()
From: Johannes Berg @ 2018-09-19 12:08 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
In nla_parse() we already set this, but it makes sense to
also do it in nla_validate() which already also sets the
bad attribute pointer.
CC: David Ahern <dsahern@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
lib/nlattr.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/nlattr.c b/lib/nlattr.c
index e2e5b38394d5..33404745bec4 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -180,9 +180,13 @@ int nla_validate(const struct nlattr *head, int len, int maxtype,
int rem;
nla_for_each_attr(nla, head, len, rem) {
- int err = validate_nla(nla, maxtype, policy, NULL);
+ static const char _msg[] = "Attribute failed policy validation";
+ const char *msg = _msg;
+ int err = validate_nla(nla, maxtype, policy, &msg);
if (err < 0) {
+ if (extack)
+ extack->_msg = msg;
NL_SET_BAD_ATTR(extack, nla);
return err;
}
--
2.14.4
^ permalink raw reply related
* [PATCH 5/7] netlink: prepare validate extack setting for recursion
From: Johannes Berg @ 2018-09-19 12:08 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
In one of my previous patches in this area I introduced code
to pass out just the error message to store in the extack, for
use in NLA_REJECT.
Change this code now to set both the error message and the bad
attribute pointer, and carry around a boolean indicating that
the values have been set.
This will be used in the next patch to allow recursive validation
of nested policies, while preserving the innermost error message
rather than overwriting it with a generic out-level message.
Note that this is a completely local change - code calling one
of nla_parse/nla_validate isn't affected, both functions continue
to overwrite any previously set message with an error generated
here, but in the next patch the message generated may come from
an inner call to nested attribute validation instead, and there
the outer (generic) message shouldn't overwrite the inner.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
lib/nlattr.c | 32 ++++++++++++++++++++------------
1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 966cd3dcf31b..2b015e43b725 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -69,7 +69,7 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
static int validate_nla(const struct nlattr *nla, int maxtype,
const struct nla_policy *policy,
- const char **error_msg)
+ struct netlink_ext_ack *extack, bool *extack_set)
{
const struct nla_policy *pt;
int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
@@ -94,8 +94,11 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
break;
case NLA_REJECT:
- if (pt->validation_data && error_msg)
- *error_msg = pt->validation_data;
+ if (pt->validation_data && extack && !*extack_set) {
+ *extack_set = true;
+ extack->_msg = pt->validation_data;
+ NL_SET_BAD_ATTR(extack, nla);
+ }
return -EINVAL;
case NLA_FLAG:
@@ -160,24 +163,25 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
static int nla_validate_parse(const struct nlattr *head, int len, int maxtype,
const struct nla_policy *policy,
- struct netlink_ext_ack *extack,
+ struct netlink_ext_ack *extack, bool *extack_set,
struct nlattr **tb)
{
const struct nlattr *nla;
int rem;
nla_for_each_attr(nla, head, len, rem) {
- static const char _msg[] = "Attribute failed policy validation";
- const char *msg = _msg;
u16 type = nla_type(nla);
if (policy) {
- int err = validate_nla(nla, maxtype, policy, &msg);
+ int err = validate_nla(nla, maxtype, policy,
+ extack, extack_set);
if (err < 0) {
- if (extack)
- extack->_msg = msg;
- NL_SET_BAD_ATTR(extack, nla);
+ if (!*extack_set) {
+ *extack_set = true;
+ NL_SET_ERR_MSG_ATTR(extack, nla,
+ "Attribute failed policy validation");
+ }
return err;
}
}
@@ -207,9 +211,11 @@ int nla_validate(const struct nlattr *head, int len, int maxtype,
const struct nla_policy *policy,
struct netlink_ext_ack *extack)
{
+ bool extack_set = false;
int rem;
- rem = nla_validate_parse(head, len, maxtype, policy, extack, NULL);
+ rem = nla_validate_parse(head, len, maxtype, policy,
+ extack, &extack_set, NULL);
if (rem < 0)
return rem;
@@ -266,11 +272,13 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
int len, const struct nla_policy *policy,
struct netlink_ext_ack *extack)
{
+ bool extack_set = false;
int rem;
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
- rem = nla_validate_parse(head, len, maxtype, policy, extack, tb);
+ rem = nla_validate_parse(head, len, maxtype, policy,
+ extack, &extack_set, tb);
if (rem < 0)
return rem;
--
2.14.4
^ permalink raw reply related
* [PATCH 6/7] netlink: allow NLA_NESTED to specify nested policy to validate
From: Johannes Berg @ 2018-09-19 12:08 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
Now that we have a validation_data pointer, and the len field in
the policy is unused for NLA_NESTED, we can allow using them both
to have nested validation. This can be nice in code, although we
still have to use nla_parse_nested() or similar which would also
take a policy; however, it also serves as documentation in the
policy without requiring a look at the code.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/netlink.h | 13 +++++++++++--
lib/nlattr.c | 17 +++++++++++++++++
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 0d698215d4d9..91907852da1c 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -200,8 +200,10 @@ enum {
* NLA_NUL_STRING Maximum length of string (excluding NUL)
* NLA_FLAG Unused
* NLA_BINARY Maximum length of attribute payload
- * NLA_NESTED Don't use `len' field -- length verification is
- * done by checking len of nested header (or empty)
+ * NLA_NESTED Length verification is done by checking len of
+ * nested header (or empty); len field is used if
+ * validation_data is also used, for the max attr
+ * number in the nested policy.
* NLA_U8, NLA_U16,
* NLA_U32, NLA_U64,
* NLA_S8, NLA_S16,
@@ -224,6 +226,10 @@ enum {
* NLA_REJECT This attribute is always rejected and validation data
* may point to a string to report as the error instead
* of the generic one in extended ACK.
+ * NLA_NESTED Points to a nested policy to validate, must also set
+ * `len' to the max attribute number.
+ * Note that nla_parse() will validate, but of course not
+ * parse, the nested sub-policies.
* All other Unused
*
* Example:
@@ -247,6 +253,9 @@ struct nla_policy {
#define NLA_POLICY_ETH_ADDR NLA_POLICY_EXACT_LEN(ETH_ALEN)
#define NLA_POLICY_ETH_ADDR_COMPAT NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN)
+#define NLA_POLICY_NESTED(maxattr, policy) \
+ { .type = NLA_NESTED, .validation_data = policy, .len = maxattr }
+
/**
* struct nl_info - netlink source information
* @nlh: Netlink message header of original request
diff --git a/lib/nlattr.c b/lib/nlattr.c
index 2b015e43b725..c0ea8a78eda6 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -67,6 +67,11 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
return 0;
}
+static int nla_validate_parse(const struct nlattr *head, int len, int maxtype,
+ const struct nla_policy *policy,
+ struct netlink_ext_ack *extack, bool *extack_set,
+ struct nlattr **tb);
+
static int validate_nla(const struct nlattr *nla, int maxtype,
const struct nla_policy *policy,
struct netlink_ext_ack *extack, bool *extack_set)
@@ -148,6 +153,18 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
*/
if (attrlen == 0)
break;
+ if (attrlen < NLA_HDRLEN)
+ return -ERANGE;
+ if (pt->validation_data) {
+ int err;
+
+ err = nla_validate_parse(nla_data(nla), nla_len(nla),
+ pt->len, pt->validation_data,
+ extack, extack_set, NULL);
+ if (err < 0)
+ return err;
+ }
+ break;
default:
if (pt->len)
minlen = pt->len;
--
2.14.4
^ permalink raw reply related
* [PATCH 7/7] netlink: add nested array policy validation
From: Johannes Berg @ 2018-09-19 12:09 UTC (permalink / raw)
To: linux-wireless, netdev; +Cc: Johannes Berg
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
From: Johannes Berg <johannes.berg@intel.com>
Sometimes nested netlink attributes are just used as arrays, with
the nla_type() of each not being used; we have this in nl80211 and
e.g. NFTA_SET_ELEM_LIST_ELEMENTS.
Add the ability to validate this type of message directly in the
policy, by adding the type NLA_NESTED_ARRAY which does exactly
this: require a first level of nesting but ignore the attribute
type, and then inside each require a second level of nested and
validate those attributes against a given policy (if present).
Note that some nested array types actually require that all of
the entries have the same index, this is possible to express in
a nested policy already, apart from the validation that only the
one allowed type is used.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/netlink.h | 12 +++++++++++-
lib/nlattr.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 91907852da1c..3698ca8ff92c 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -172,6 +172,7 @@ enum {
NLA_FLAG,
NLA_MSECS,
NLA_NESTED,
+ NLA_NESTED_ARRAY,
NLA_NUL_STRING,
NLA_BINARY,
NLA_S8,
@@ -200,7 +201,8 @@ enum {
* NLA_NUL_STRING Maximum length of string (excluding NUL)
* NLA_FLAG Unused
* NLA_BINARY Maximum length of attribute payload
- * NLA_NESTED Length verification is done by checking len of
+ * NLA_NESTED,
+ * NLA_NESTED_ARRAY Length verification is done by checking len of
* nested header (or empty); len field is used if
* validation_data is also used, for the max attr
* number in the nested policy.
@@ -230,6 +232,12 @@ enum {
* `len' to the max attribute number.
* Note that nla_parse() will validate, but of course not
* parse, the nested sub-policies.
+ * NLA_NESTED_ARRAY Points to a nested policy to validate, must also set
+ * `len' to the max attribute number. The difference to
+ * NLA_NESTED is the structure - NLA_NESTED has the
+ * nested attributes directly inside, while an array has
+ * the nested attributes at another level down and the
+ * attributes directly in the nesting don't matter.
* All other Unused
*
* Example:
@@ -255,6 +263,8 @@ struct nla_policy {
#define NLA_POLICY_NESTED(maxattr, policy) \
{ .type = NLA_NESTED, .validation_data = policy, .len = maxattr }
+#define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \
+ { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr }
/**
* struct nl_info - netlink source information
diff --git a/lib/nlattr.c b/lib/nlattr.c
index c0ea8a78eda6..234763b41ab7 100644
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -72,6 +72,35 @@ static int nla_validate_parse(const struct nlattr *head, int len, int maxtype,
struct netlink_ext_ack *extack, bool *extack_set,
struct nlattr **tb);
+static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
+ const struct nla_policy *policy,
+ struct netlink_ext_ack *extack, bool *extack_set)
+{
+ const struct nlattr *entry;
+ int rem;
+
+ nla_for_each_attr(entry, head, len, rem) {
+ int ret;
+
+ if (nla_len(entry) == 0)
+ continue;
+
+ if (nla_len(entry) < NLA_HDRLEN) {
+ NL_SET_ERR_MSG_ATTR(extack, entry,
+ "Array element too short");
+ return -ERANGE;
+ }
+
+ ret = nla_validate_parse(nla_data(entry), nla_len(entry),
+ maxtype, policy, extack, extack_set,
+ NULL);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int validate_nla(const struct nlattr *nla, int maxtype,
const struct nla_policy *policy,
struct netlink_ext_ack *extack, bool *extack_set)
@@ -165,6 +194,24 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
return err;
}
break;
+ case NLA_NESTED_ARRAY:
+ /* a nested array attribute is allowed to be empty; if its not,
+ * it must have a size of at least NLA_HDRLEN.
+ */
+ if (attrlen == 0)
+ break;
+ if (attrlen < NLA_HDRLEN)
+ return -ERANGE;
+ if (pt->validation_data) {
+ int err;
+
+ err = nla_validate_array(nla_data(nla), nla_len(nla),
+ pt->len, pt->validation_data,
+ extack, extack_set);
+ if (err < 0)
+ return err;
+ }
+ break;
default:
if (pt->len)
minlen = pt->len;
--
2.14.4
^ permalink raw reply related
* Re: [PATCH 0/7] netlink recursive policy validation
From: Johannes Berg @ 2018-09-19 12:15 UTC (permalink / raw)
To: linux-wireless, netdev
In-Reply-To: <20180919120900.28708-1-johannes@sipsolutions.net>
Below is an example of a policy I just built using this.
This may seem rather complex, but that's because the problem is complex
- we want to be able to measure multiple different things (currently
only FTM though) with different peers, and some attributes are shared
(like channel, MAC address) whereas others are method-specific...
I'm sticking all of the measurement request into a single top-level
nl80211 attribute (NL80211_ATTR_PEER_MEASUREMENTS), then in there you
specify global parameters (elided) as well as an array of peers.
Each peer again contains some method-independent parameters (only "CHAN"
shown), as well as request data, which has some parts that are common
and some that are method dependent (yet another nesting level).
All of this gets validated - with the channel data exception in the
comment below - entirely without ever writing another line of code for
it. Yes, we'll still have to write some code to actually use it, but
then we need to worry much less about formatting there.
johannes
static const struct nla_policy
nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
/* ... */
};
static const struct nla_policy
nl80211_pmsr_req_data_policy[NL80211_PMSR_TYPE_MAX + 1] = {
[NL80211_PMSR_TYPE_FTM] =
NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
nl80211_pmsr_ftm_req_attr_policy),
};
static const struct nla_policy
nl80211_pmsr_req_attr_policy[NL80211_PMSR_REQ_ATTR_MAX + 1] = {
[NL80211_PMSR_REQ_ATTR_DATA] =
NLA_POLICY_NESTED(NL80211_PMSR_TYPE_MAX,
nl80211_pmsr_req_data_policy),
/* ... */
};
static const struct nla_policy
nl80211_psmr_peer_attr_policy[NL80211_PMSR_PEER_ATTR_MAX + 1] = {
/*
* we could specify this again to be the top-level policy,
* but that would open us up to recursion problems ...
*/
[NL80211_PMSR_PEER_ATTR_CHAN] = { .type = NLA_NESTED },
[NL80211_PMSR_PEER_ATTR_REQ] =
NLA_POLICY_NESTED(NL80211_PMSR_REQ_ATTR_MAX,
nl80211_pmsr_req_attr_policy),
/* ... */
};
static const struct nla_policy
nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
[NL80211_PMSR_ATTR_PEERS] =
NLA_POLICY_NESTED_ARRAY(NL80211_PMSR_PEER_ATTR_MAX,
nl80211_psmr_peer_attr_policy),
/* ... */
};
static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
/* ... */
[NL80211_ATTR_PEER_MEASUREMENTS] =
NLA_POLICY_NESTED(NL80211_PMSR_FTM_REQ_ATTR_MAX,
nl80211_pmsr_attr_policy),
};
^ permalink raw reply
* Re: [PATCH v2 2/4] dt-bindings: net: qcom: Add binding for shared mdio bus
From: Andrew Lunn @ 2018-09-19 12:25 UTC (permalink / raw)
To: Wang, Dongsheng
Cc: Florian Fainelli, timur@kernel.org, davem@davemloft.net,
Zheng, Joey, netdev@vger.kernel.org, devicetree@vger.kernel.org
In-Reply-To: <7696bcd8ca594b1da683b437197b4ddf@HXTBJIDCEMVIW02.hxtcorp.net>
On Wed, Sep 19, 2018 at 09:19:19AM +0000, Wang, Dongsheng wrote:
> On 2018/9/18 20:35, Andrew Lunn wrote:
> >>> If you want to describe the MDIO controller, then you embed a mdio
> >>> subnode into your Ethernet MAC node:
> >>>
> >>> emac0: ethernet@feb20000 {
> >>> mdio {
> >>> #address-cells = <1>;
> >>> #size-cells = <0>;
> >>>
> >>> phy0: ethernet-phy@0 {
> >>> reg = <0>;
> >>> };
> >>> };
> >>> };
> >>>
> >>> And then each Ethernet MAC controller refers to their appropriate PHY
> >>> device tree node using a phy-handle property to point to either their
> >>> own MDIO controller, or another MAC's MDIO controller.
> >> Sorry, I do not understand how phy-handle point to MDIO controller,
> >> because phy-handle is defined to point to a phy.
> > The MAC driver does not care what MDIO controller a PHY is on. All you
> > need to do to register the PHY is:
>
> Yes, these are all things that must be done, and emac driver will
> connect phy when mac up.
> If we had a separate MDIO controller, the MAC would not care about MDIO
> bus. But MDIO is integrated within the EMAC, and emac driver maintains
> the mdio.
>
> Each EMAC do their mdio register/unregister. But in the shared scenario,
> the EMACs that use the shared bus do not need to create an MDIO and
> cannot release the Shared bus.
Hi Dongsheng
There is nothing new here. Many Ethernet drivers export an MDIO bus
which is then used by some other device, often an Ethernet
switch. Ordering should not be a problem, you just need to handle
EPROBE_DEFER, which will happen if the MDIO bus has not yet been
probed when you try to lookup the phy-handle. And once the phy has
been connected, the MDIO bus will be locked, preventing it from being
removed.
> But ACPI environment my understand is this:
ACPI is completely separate and should not affect the DT binding.
I've not yet looked at the ACPI changes you added.
> I will rework this patchset and maybe patches will be a delay for a few
> days.
Thanks
Andrew
^ permalink raw reply
* Re: [PATCH] net: macb: Clean 64b dma addresses if they are not detected
From: Edgar E. Iglesias @ 2018-09-19 18:08 UTC (permalink / raw)
To: Michal Simek
Cc: linux-kernel, monstr, Edgar E. Iglesias, David S. Miller, netdev,
u-boot, Joe Hershberger, Nicolas Ferre
In-Reply-To: <0997a0e77b5e5c04c9a4d277d702d93a1a8a7448.1537373294.git.michal.simek@xilinx.com>
On Wed, Sep 19, 2018 at 06:08:18PM +0200, Michal Simek wrote:
> Clear ADDR64 dma bit in DMACFG register in case that HW_DMA_CAP_64B
> is not detected on 64bit system.
> The issue was observed when bootloader(u-boot) does not check macb
> feature at DCFG6 register (DAW64_OFFSET) and enabling 64bit dma support
> by default. Then macb driver is reading DMACFG register back and only
> adding 64bit dma configuration but not cleaning it out.
>
> This is also align with other features which are also cleared if they are not
> present.
Hi Michal,
>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> ---
>
> drivers/net/ethernet/cadence/macb_main.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
> index 16e4ef7d7185..79707dff3f13 100644
> --- a/drivers/net/ethernet/cadence/macb_main.c
> +++ b/drivers/net/ethernet/cadence/macb_main.c
> @@ -2163,6 +2163,8 @@ static void macb_configure_dma(struct macb *bp)
> #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
> if (bp->hw_dma_cap & HW_DMA_CAP_64B)
> dmacfg |= GEM_BIT(ADDR64);
> + else
> + dmacfg &= ~GEM_BIT(ADDR64);
> #endif
I think you might want to do this clearing outside of the #ifdef.
If CONFIG_ARCH_DMA_ADDR_T_64BIT is not defined, we'd want to make
sure the ADDR64 is cleared. E.g something like:
dmacfg &= ~GEM_BIT(ADDR64);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
if (bp->hw_dma_cap & HW_DMA_CAP_64B)
dmacfg |= GEM_BIT(ADDR64);
#endif
Same thing for the USE_HWSTAMP/PTP flags below.
Best regards,
Edgar
> #ifdef CONFIG_MACB_USE_HWSTAMP
> if (bp->hw_dma_cap & HW_DMA_CAP_PTP)
> --
> 1.9.1
>
^ permalink raw reply
* Re: [PATCH v3 net-next 07/12] net: ethernet: Add helper to remove a supported link mode
From: Andrew Lunn @ 2018-09-19 12:32 UTC (permalink / raw)
To: Simon Horman
Cc: David Miller, netdev, Florian Fainelli, Sergei Shtylyov,
linux-renesas-soc
In-Reply-To: <20180919074557.vixjj3rg76ayy3k7@verge.net.au>
> > And here also.
>
> Thanks for raising this, I noticed it too.
>
> > Looking at the code, i see:
> >
> > /* E-MAC init function */
> > static void ravb_emac_init(struct net_device *ndev)
> > {
> > struct ravb_private *priv = netdev_priv(ndev);
> >
> > /* Receive frame limit set register */
> > ravb_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN, RFLR);
> >
> > /* EMAC Mode: PAUSE prohibition; Duplex; RX Checksum; TX; RX */
> > ravb_write(ndev, ECMR_ZPF | (priv->duplex ? ECMR_DM : 0) |
> > (ndev->features & NETIF_F_RXCSUM ? ECMR_RCSC : 0) |
> > ECMR_TE | ECMR_RE, ECMR);
> >
> > Does this mean Pause is not supported in the hardware?
>
> According to my reading of the documentation Pause is supported by the
> hardware and the above code seems to conflict with the comment (possibly
> both the code and comment predate the current documentation). My reading of
> the documentation is that the above unconditionally _enables_ receiving and
> sending Pause frames with time parameter value 0.
Hi Simon
We should first prove that this additional Pause is causing the
issue. After that, we can decide if we want to add Pause support to
the driver. Please could you test this patch.
Thanks
Andrew
>From 0f69f4991454d48f34b05d5dc006c04a180c7842 Mon Sep 17 00:00:00 2001
From: Andrew Lunn <andrew@lunn.ch>
Date: Tue, 18 Sep 2018 18:12:54 -0500
Subject: [PATCH] ravb: Disable Pause Advertisement
The previous commit to ravb had the side effect of making the PHY
advertise Pause. This previously did not happen, and it appears the
MAC does not support Pause. By default, phydev->supported has Pause
enabled, but phydev->advertising does not. Rather than rely on this,
be explicit, and remove the Pause link mode.
Reported-by: Simon Horman <horms@verge.net.au>
Fixes: 41124fa64d4b ("net: ethernet: Add helper to remove a supported link mode")
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/ethernet/renesas/ravb_main.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index fb2a1125780d..d7630c0fdb0a 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -1073,9 +1073,10 @@ static int ravb_phy_init(struct net_device *ndev)
netdev_info(ndev, "limited PHY to 100Mbit/s\n");
}
- /* 10BASE is not supported */
+ /* 10BASE and Pause is not supported */
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT);
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT);
+ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_Pause_BIT);
phy_attached_info(phydev);
--
2.19.0.rc1
^ permalink raw reply related
* [PATCH 1/5] batman-adv: Start new development cycle
From: Simon Wunderlich @ 2018-09-19 12:32 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Simon Wunderlich
In-Reply-To: <20180919123238.23742-1-sw@simonwunderlich.de>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/main.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 8da3c9336111..2002b70e18db 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -25,7 +25,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2018.2"
+#define BATADV_SOURCE_VERSION "2018.4"
#endif
/* B.A.T.M.A.N. parameters */
--
2.11.0
^ permalink raw reply related
* [PATCH 2/5] batman-adv: Mark debugfs functionality as deprecated
From: Simon Wunderlich @ 2018-09-19 12:32 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20180919123238.23742-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
CONFIG_BATMAN_ADV_DEBUGFS is disabled by default because debugfs is not
supported for batman-adv interfaces in any non-default netns. Any remaining
users of this interface should still be informed about the deprecation and
the generic netlink alternative.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/debugfs.c | 37 +++++++++++++++++++++++++++++++++++++
net/batman-adv/debugfs.h | 6 ++++++
net/batman-adv/icmp_socket.c | 3 +++
net/batman-adv/log.c | 4 ++++
4 files changed, 50 insertions(+)
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c
index 3cb82378300b..8b608a2e2653 100644
--- a/net/batman-adv/debugfs.c
+++ b/net/batman-adv/debugfs.c
@@ -47,8 +47,24 @@
static struct dentry *batadv_debugfs;
+/**
+ * batadv_debugfs_deprecated() - Log use of deprecated batadv debugfs access
+ * @file: file which was accessed
+ * @alt: explanation what can be used as alternative
+ */
+void batadv_debugfs_deprecated(struct file *file, const char *alt)
+{
+ struct dentry *dentry = file_dentry(file);
+ const char *name = dentry->d_name.name;
+
+ pr_warn_ratelimited(DEPRECATED "%s (pid %d) Use of debugfs file \"%s\".\n%s",
+ current->comm, task_pid_nr(current), name, alt);
+}
+
static int batadv_algorithms_open(struct inode *inode, struct file *file)
{
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_ROUTING_ALGOS instead\n");
return single_open(file, batadv_algo_seq_print_text, NULL);
}
@@ -56,6 +72,8 @@ static int neighbors_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_NEIGHBORS instead\n");
return single_open(file, batadv_hardif_neigh_seq_print_text, net_dev);
}
@@ -63,6 +81,8 @@ static int batadv_originators_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_ORIGINATORS instead\n");
return single_open(file, batadv_orig_seq_print_text, net_dev);
}
@@ -79,6 +99,8 @@ static int batadv_originators_hardif_open(struct inode *inode,
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_HARDIFS instead\n");
return single_open(file, batadv_orig_hardif_seq_print_text, net_dev);
}
@@ -86,6 +108,8 @@ static int batadv_gateways_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_GATEWAYS instead\n");
return single_open(file, batadv_gw_client_seq_print_text, net_dev);
}
@@ -93,6 +117,8 @@ static int batadv_transtable_global_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_TRANSTABLE_GLOBAL instead\n");
return single_open(file, batadv_tt_global_seq_print_text, net_dev);
}
@@ -101,6 +127,8 @@ static int batadv_bla_claim_table_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_BLA_CLAIM instead\n");
return single_open(file, batadv_bla_claim_table_seq_print_text,
net_dev);
}
@@ -110,6 +138,8 @@ static int batadv_bla_backbone_table_open(struct inode *inode,
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_BLA_BACKBONE instead\n");
return single_open(file, batadv_bla_backbone_table_seq_print_text,
net_dev);
}
@@ -128,6 +158,8 @@ static int batadv_dat_cache_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_DAT_CACHE instead\n");
return single_open(file, batadv_dat_cache_seq_print_text, net_dev);
}
#endif
@@ -136,6 +168,8 @@ static int batadv_transtable_local_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_TRANSTABLE_LOCAL instead\n");
return single_open(file, batadv_tt_local_seq_print_text, net_dev);
}
@@ -149,6 +183,7 @@ static int batadv_nc_nodes_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file, "");
return single_open(file, batadv_nc_nodes_seq_print_text, net_dev);
}
#endif
@@ -165,6 +200,8 @@ static int batadv_mcast_flags_open(struct inode *inode, struct file *file)
{
struct net_device *net_dev = (struct net_device *)inode->i_private;
+ batadv_debugfs_deprecated(file,
+ "Use genl command BATADV_CMD_GET_MCAST_FLAGS instead\n");
return single_open(file, batadv_mcast_flags_seq_print_text, net_dev);
}
#endif
diff --git a/net/batman-adv/debugfs.h b/net/batman-adv/debugfs.h
index 08a592ffbee5..8de018e5c577 100644
--- a/net/batman-adv/debugfs.h
+++ b/net/batman-adv/debugfs.h
@@ -21,12 +21,14 @@
#include "main.h"
+struct file;
struct net_device;
#define BATADV_DEBUGFS_SUBDIR "batman_adv"
#if IS_ENABLED(CONFIG_BATMAN_ADV_DEBUGFS)
+void batadv_debugfs_deprecated(struct file *file, const char *alt);
void batadv_debugfs_init(void);
void batadv_debugfs_destroy(void);
int batadv_debugfs_add_meshif(struct net_device *dev);
@@ -38,6 +40,10 @@ void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface);
#else
+static inline void batadv_debugfs_deprecated(struct file *file, const char *alt)
+{
+}
+
static inline void batadv_debugfs_init(void)
{
}
diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c
index 55c358ad3331..d70f363c52ae 100644
--- a/net/batman-adv/icmp_socket.c
+++ b/net/batman-adv/icmp_socket.c
@@ -47,6 +47,7 @@
#include <linux/wait.h>
#include <uapi/linux/batadv_packet.h>
+#include "debugfs.h"
#include "hard-interface.h"
#include "log.h"
#include "originator.h"
@@ -74,6 +75,8 @@ static int batadv_socket_open(struct inode *inode, struct file *file)
if (!try_module_get(THIS_MODULE))
return -EBUSY;
+ batadv_debugfs_deprecated(file, "");
+
nonseekable_open(inode, file);
socket_client = kmalloc(sizeof(*socket_client), GFP_KERNEL);
diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c
index 853773e45f79..1032d84e21ae 100644
--- a/net/batman-adv/log.c
+++ b/net/batman-adv/log.c
@@ -40,6 +40,8 @@
#include <linux/wait.h>
#include <stdarg.h>
+#include "debugfs.h"
+
#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
@@ -115,6 +117,8 @@ static int batadv_log_open(struct inode *inode, struct file *file)
if (!try_module_get(THIS_MODULE))
return -EBUSY;
+ batadv_debugfs_deprecated(file, "");
+
nonseekable_open(inode, file);
file->private_data = inode->i_private;
return 0;
--
2.11.0
^ permalink raw reply related
* [PATCH 5/5] batman-adv: Enable LockLess TX for softif
From: Simon Wunderlich @ 2018-09-19 12:32 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20180919123238.23742-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
The batadv interfaces are virtual interfaces which just tunnel the traffic
over other ethernet compatible interfaces. It doesn't need serialization
during the tx phase and is using RCU for most of its internal
datastructures. Since it doesn't have actual queues which could be locked
independently, the throughput gets significantly reduced by the extra lock
in the core net code.
8 parallel TCP connections forwarded by an IPQ4019 based hardware over
5GHz could reach:
* without LLTX: 349 Mibit/s
* with LLTX: 563 Mibit/s
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/soft-interface.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index e121c59fc1fa..2c7d95727f90 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -1050,6 +1050,7 @@ static void batadv_softif_init_early(struct net_device *dev)
dev->needs_free_netdev = true;
dev->priv_destructor = batadv_softif_free;
dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_NETNS_LOCAL;
+ dev->features |= NETIF_F_LLTX;
dev->priv_flags |= IFF_NO_QUEUE;
/* can't call min_mtu, because the needed variables
--
2.11.0
^ permalink raw reply related
* [PATCH 4/5] batman-adv: Move OGM rebroadcast stats to orig_ifinfo
From: Simon Wunderlich @ 2018-09-19 12:32 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20180919123238.23742-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
B.A.T.M.A.N. IV requires the number of rebroadcast from a neighboring
originator. These statistics are gathered per interface which transmitted
the OGM (and then received it again). Since an originator is not interface
specific, a resizable array was used in each originator.
This resizable array had an entry for each interface and had to be resizes
(for all OGMs) when the number of active interface was modified. This could
cause problems when a large number of interface is added and not enough
continuous memory is available to allocate the array.
There is already a per interface originator structure "batadv_orig_ifinfo"
which can be used to store this information.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/bat_iv_ogm.c | 330 ++++++++++++----------------------------
net/batman-adv/hard-interface.c | 47 +++---
net/batman-adv/originator.c | 107 -------------
net/batman-adv/originator.h | 4 -
net/batman-adv/soft-interface.c | 1 -
net/batman-adv/types.h | 62 +++-----
6 files changed, 145 insertions(+), 406 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 73bf6a93a3cf..d2227091029f 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -138,169 +138,6 @@ static u8 batadv_ring_buffer_avg(const u8 lq_recv[])
}
/**
- * batadv_iv_ogm_orig_free() - free the private resources allocated for this
- * orig_node
- * @orig_node: the orig_node for which the resources have to be free'd
- */
-static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node)
-{
- kfree(orig_node->bat_iv.bcast_own);
- kfree(orig_node->bat_iv.bcast_own_sum);
-}
-
-/**
- * batadv_iv_ogm_orig_add_if() - change the private structures of the orig_node
- * to include the new hard-interface
- * @orig_node: the orig_node that has to be changed
- * @max_if_num: the current amount of interfaces
- *
- * Return: 0 on success, a negative error code otherwise.
- */
-static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node,
- unsigned int max_if_num)
-{
- void *data_ptr;
- size_t old_size;
- int ret = -ENOMEM;
-
- spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
-
- old_size = (max_if_num - 1) * sizeof(unsigned long) * BATADV_NUM_WORDS;
- data_ptr = kmalloc_array(max_if_num,
- BATADV_NUM_WORDS * sizeof(unsigned long),
- GFP_ATOMIC);
- if (!data_ptr)
- goto unlock;
-
- memcpy(data_ptr, orig_node->bat_iv.bcast_own, old_size);
- kfree(orig_node->bat_iv.bcast_own);
- orig_node->bat_iv.bcast_own = data_ptr;
-
- data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
- if (!data_ptr)
- goto unlock;
-
- memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum,
- (max_if_num - 1) * sizeof(u8));
- kfree(orig_node->bat_iv.bcast_own_sum);
- orig_node->bat_iv.bcast_own_sum = data_ptr;
-
- ret = 0;
-
-unlock:
- spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
-
- return ret;
-}
-
-/**
- * batadv_iv_ogm_drop_bcast_own_entry() - drop section of bcast_own
- * @orig_node: the orig_node that has to be changed
- * @max_if_num: the current amount of interfaces
- * @del_if_num: the index of the interface being removed
- */
-static void
-batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node,
- unsigned int max_if_num,
- unsigned int del_if_num)
-{
- size_t chunk_size;
- size_t if_offset;
- void *data_ptr;
-
- lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock);
-
- chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS;
- data_ptr = kmalloc_array(max_if_num, chunk_size, GFP_ATOMIC);
- if (!data_ptr)
- /* use old buffer when new one could not be allocated */
- data_ptr = orig_node->bat_iv.bcast_own;
-
- /* copy first part */
- memmove(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size);
-
- /* copy second part */
- if_offset = (del_if_num + 1) * chunk_size;
- memmove((char *)data_ptr + del_if_num * chunk_size,
- (uint8_t *)orig_node->bat_iv.bcast_own + if_offset,
- (max_if_num - del_if_num) * chunk_size);
-
- /* bcast_own was shrunk down in new buffer; free old one */
- if (orig_node->bat_iv.bcast_own != data_ptr) {
- kfree(orig_node->bat_iv.bcast_own);
- orig_node->bat_iv.bcast_own = data_ptr;
- }
-}
-
-/**
- * batadv_iv_ogm_drop_bcast_own_sum_entry() - drop section of bcast_own_sum
- * @orig_node: the orig_node that has to be changed
- * @max_if_num: the current amount of interfaces
- * @del_if_num: the index of the interface being removed
- */
-static void
-batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node,
- unsigned int max_if_num,
- unsigned int del_if_num)
-{
- size_t if_offset;
- void *data_ptr;
-
- lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock);
-
- data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
- if (!data_ptr)
- /* use old buffer when new one could not be allocated */
- data_ptr = orig_node->bat_iv.bcast_own_sum;
-
- memmove(data_ptr, orig_node->bat_iv.bcast_own_sum,
- del_if_num * sizeof(u8));
-
- if_offset = (del_if_num + 1) * sizeof(u8);
- memmove((char *)data_ptr + del_if_num * sizeof(u8),
- orig_node->bat_iv.bcast_own_sum + if_offset,
- (max_if_num - del_if_num) * sizeof(u8));
-
- /* bcast_own_sum was shrunk down in new buffer; free old one */
- if (orig_node->bat_iv.bcast_own_sum != data_ptr) {
- kfree(orig_node->bat_iv.bcast_own_sum);
- orig_node->bat_iv.bcast_own_sum = data_ptr;
- }
-}
-
-/**
- * batadv_iv_ogm_orig_del_if() - change the private structures of the orig_node
- * to exclude the removed interface
- * @orig_node: the orig_node that has to be changed
- * @max_if_num: the current amount of interfaces
- * @del_if_num: the index of the interface being removed
- *
- * Return: 0 on success, a negative error code otherwise.
- */
-static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
- unsigned int max_if_num,
- unsigned int del_if_num)
-{
- spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
-
- if (max_if_num == 0) {
- kfree(orig_node->bat_iv.bcast_own);
- kfree(orig_node->bat_iv.bcast_own_sum);
- orig_node->bat_iv.bcast_own = NULL;
- orig_node->bat_iv.bcast_own_sum = NULL;
- } else {
- batadv_iv_ogm_drop_bcast_own_entry(orig_node, max_if_num,
- del_if_num);
- batadv_iv_ogm_drop_bcast_own_sum_entry(orig_node, max_if_num,
- del_if_num);
- }
-
- spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
-
- return 0;
-}
-
-/**
* batadv_iv_ogm_orig_get() - retrieve or create (if does not exist) an
* originator
* @bat_priv: the bat priv with all the soft interface information
@@ -315,7 +152,6 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
{
struct batadv_orig_node *orig_node;
int hash_added;
- size_t size;
orig_node = batadv_orig_hash_find(bat_priv, addr);
if (orig_node)
@@ -327,16 +163,6 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
spin_lock_init(&orig_node->bat_iv.ogm_cnt_lock);
- size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS;
- orig_node->bat_iv.bcast_own = kzalloc(size, GFP_ATOMIC);
- if (!orig_node->bat_iv.bcast_own)
- goto free_orig_node;
-
- size = bat_priv->num_ifaces * sizeof(u8);
- orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC);
- if (!orig_node->bat_iv.bcast_own_sum)
- goto free_orig_node;
-
kref_get(&orig_node->refcount);
hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig,
batadv_choose_orig, orig_node,
@@ -347,8 +173,9 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
return orig_node;
free_orig_node_hash:
+ /* reference for batadv_hash_add */
batadv_orig_node_put(orig_node);
-free_orig_node:
+ /* reference from batadv_orig_node_new */
batadv_orig_node_put(orig_node);
return NULL;
@@ -893,26 +720,30 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
struct batadv_hashtable *hash = bat_priv->orig_hash;
struct hlist_head *head;
struct batadv_orig_node *orig_node;
+ struct batadv_orig_ifinfo *orig_ifinfo;
unsigned long *word;
u32 i;
- size_t word_index;
u8 *w;
- unsigned int if_num;
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
- spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
- word_index = hard_iface->if_num * BATADV_NUM_WORDS;
- word = &orig_node->bat_iv.bcast_own[word_index];
-
- batadv_bit_get_packet(bat_priv, word, 1, 0);
- if_num = hard_iface->if_num;
- w = &orig_node->bat_iv.bcast_own_sum[if_num];
- *w = bitmap_weight(word, BATADV_TQ_LOCAL_WINDOW_SIZE);
- spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+ hlist_for_each_entry_rcu(orig_ifinfo,
+ &orig_node->ifinfo_list,
+ list) {
+ if (orig_ifinfo->if_outgoing != hard_iface)
+ continue;
+
+ spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+ word = orig_ifinfo->bat_iv.bcast_own;
+ batadv_bit_get_packet(bat_priv, word, 1, 0);
+ w = &orig_ifinfo->bat_iv.bcast_own_sum;
+ *w = bitmap_weight(word,
+ BATADV_TQ_LOCAL_WINDOW_SIZE);
+ spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+ }
}
rcu_read_unlock();
}
@@ -1000,6 +831,35 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
}
/**
+ * batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over iterface
+ * @orig_node: originator which reproadcasted the OGMs directly
+ * @if_outgoing: interface which transmitted the original OGM and received the
+ * direct rebroadcast
+ *
+ * Return: Number of replied (rebroadcasted) OGMs which were transmitted by
+ * an originator and directly (without intermediate hop) received by a specific
+ * interface
+ */
+static u8 batadv_iv_orig_ifinfo_sum(struct batadv_orig_node *orig_node,
+ struct batadv_hard_iface *if_outgoing)
+{
+ struct batadv_orig_ifinfo *orig_ifinfo;
+ u8 sum;
+
+ orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_outgoing);
+ if (!orig_ifinfo)
+ return 0;
+
+ spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+ sum = orig_ifinfo->bat_iv.bcast_own_sum;
+ spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+
+ batadv_orig_ifinfo_put(orig_ifinfo);
+
+ return sum;
+}
+
+/**
* batadv_iv_ogm_orig_update() - use OGM to update corresponding data in an
* originator
* @bat_priv: the bat priv with all the soft interface information
@@ -1026,8 +886,6 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
struct batadv_neigh_node *neigh_node = NULL;
struct batadv_neigh_node *tmp_neigh_node = NULL;
struct batadv_neigh_node *router = NULL;
- struct batadv_orig_node *orig_node_tmp;
- unsigned int if_num;
u8 sum_orig, sum_neigh;
u8 *neigh_addr;
u8 tq_avg;
@@ -1132,18 +990,10 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
*/
if (router_ifinfo &&
neigh_ifinfo->bat_iv.tq_avg == router_ifinfo->bat_iv.tq_avg) {
- orig_node_tmp = router->orig_node;
- spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
- if_num = router->if_incoming->if_num;
- sum_orig = orig_node_tmp->bat_iv.bcast_own_sum[if_num];
- spin_unlock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
-
- orig_node_tmp = neigh_node->orig_node;
- spin_lock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
- if_num = neigh_node->if_incoming->if_num;
- sum_neigh = orig_node_tmp->bat_iv.bcast_own_sum[if_num];
- spin_unlock_bh(&orig_node_tmp->bat_iv.ogm_cnt_lock);
-
+ sum_orig = batadv_iv_orig_ifinfo_sum(router->orig_node,
+ router->if_incoming);
+ sum_neigh = batadv_iv_orig_ifinfo_sum(neigh_node->orig_node,
+ neigh_node->if_incoming);
if (sum_orig >= sum_neigh)
goto out;
}
@@ -1186,7 +1036,6 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
u8 total_count;
u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
- unsigned int if_num;
unsigned int tq_asym_penalty, inv_asym_penalty;
unsigned int combined_tq;
unsigned int tq_iface_penalty;
@@ -1227,9 +1076,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
orig_node->last_seen = jiffies;
/* find packet count of corresponding one hop neighbor */
- spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
- if_num = if_incoming->if_num;
- orig_eq_count = orig_neigh_node->bat_iv.bcast_own_sum[if_num];
+ orig_eq_count = batadv_iv_orig_ifinfo_sum(orig_neigh_node, if_incoming);
neigh_ifinfo = batadv_neigh_ifinfo_new(neigh_node, if_outgoing);
if (neigh_ifinfo) {
neigh_rq_count = neigh_ifinfo->bat_iv.real_packet_count;
@@ -1237,7 +1084,6 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
} else {
neigh_rq_count = 0;
}
- spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
/* pay attention to not get a value bigger than 100 % */
if (orig_eq_count > neigh_rq_count)
@@ -1622,6 +1468,49 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
}
/**
+ * batadv_iv_ogm_process_reply() - Check OGM for direct reply and process it
+ * @ogm_packet: rebroadcast OGM packet to process
+ * @if_incoming: the interface where this packet was received
+ * @orig_node: originator which reproadcasted the OGMs
+ * @if_incoming_seqno: OGM sequence number when rebroadcast was received
+ */
+static void batadv_iv_ogm_process_reply(struct batadv_ogm_packet *ogm_packet,
+ struct batadv_hard_iface *if_incoming,
+ struct batadv_orig_node *orig_node,
+ u32 if_incoming_seqno)
+{
+ struct batadv_orig_ifinfo *orig_ifinfo;
+ s32 bit_pos;
+ u8 *weight;
+
+ /* neighbor has to indicate direct link and it has to
+ * come via the corresponding interface
+ */
+ if (!(ogm_packet->flags & BATADV_DIRECTLINK))
+ return;
+
+ if (!batadv_compare_eth(if_incoming->net_dev->dev_addr,
+ ogm_packet->orig))
+ return;
+
+ orig_ifinfo = batadv_orig_ifinfo_get(orig_node, if_incoming);
+ if (!orig_ifinfo)
+ return;
+
+ /* save packet seqno for bidirectional check */
+ spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+ bit_pos = if_incoming_seqno - 2;
+ bit_pos -= ntohl(ogm_packet->seqno);
+ batadv_set_bit(orig_ifinfo->bat_iv.bcast_own, bit_pos);
+ weight = &orig_ifinfo->bat_iv.bcast_own_sum;
+ *weight = bitmap_weight(orig_ifinfo->bat_iv.bcast_own,
+ BATADV_TQ_LOCAL_WINDOW_SIZE);
+ spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+
+ batadv_orig_ifinfo_put(orig_ifinfo);
+}
+
+/**
* batadv_iv_ogm_process() - process an incoming batman iv OGM
* @skb: the skb containing the OGM
* @ogm_offset: offset to the OGM which should be processed (for aggregates)
@@ -1705,37 +1594,13 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
}
if (is_my_orig) {
- unsigned long *word;
- size_t offset;
- s32 bit_pos;
- unsigned int if_num;
- u8 *weight;
-
orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
ethhdr->h_source);
if (!orig_neigh_node)
return;
- /* neighbor has to indicate direct link and it has to
- * come via the corresponding interface
- * save packet seqno for bidirectional check
- */
- if (has_directlink_flag &&
- batadv_compare_eth(if_incoming->net_dev->dev_addr,
- ogm_packet->orig)) {
- if_num = if_incoming->if_num;
- offset = if_num * BATADV_NUM_WORDS;
-
- spin_lock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
- word = &orig_neigh_node->bat_iv.bcast_own[offset];
- bit_pos = if_incoming_seqno - 2;
- bit_pos -= ntohl(ogm_packet->seqno);
- batadv_set_bit(word, bit_pos);
- weight = &orig_neigh_node->bat_iv.bcast_own_sum[if_num];
- *weight = bitmap_weight(word,
- BATADV_TQ_LOCAL_WINDOW_SIZE);
- spin_unlock_bh(&orig_neigh_node->bat_iv.ogm_cnt_lock);
- }
+ batadv_iv_ogm_process_reply(ogm_packet, if_incoming,
+ orig_neigh_node, if_incoming_seqno);
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"Drop packet: originator packet from myself (via neighbor)\n");
@@ -2844,9 +2709,6 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
.print = batadv_iv_ogm_orig_print,
#endif
.dump = batadv_iv_ogm_orig_dump,
- .free = batadv_iv_ogm_orig_free,
- .add_if = batadv_iv_ogm_orig_add_if,
- .del_if = batadv_iv_ogm_orig_del_if,
},
.gw = {
.init_sel_class = batadv_iv_init_sel_class,
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 2f0d42f2f913..781c5b6e6e8e 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -763,11 +763,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
hard_iface->soft_iface = soft_iface;
bat_priv = netdev_priv(hard_iface->soft_iface);
- if (bat_priv->num_ifaces >= UINT_MAX) {
- ret = -ENOSPC;
- goto err_dev;
- }
-
ret = netdev_master_upper_dev_link(hard_iface->net_dev,
soft_iface, NULL, NULL, NULL);
if (ret)
@@ -777,16 +772,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (ret < 0)
goto err_upper;
- hard_iface->if_num = bat_priv->num_ifaces;
- bat_priv->num_ifaces++;
hard_iface->if_status = BATADV_IF_INACTIVE;
- ret = batadv_orig_hash_add_if(hard_iface, bat_priv->num_ifaces);
- if (ret < 0) {
- bat_priv->algo_ops->iface.disable(hard_iface);
- bat_priv->num_ifaces--;
- hard_iface->if_status = BATADV_IF_NOT_IN_USE;
- goto err_upper;
- }
kref_get(&hard_iface->refcount);
hard_iface->batman_adv_ptype.type = ethertype;
@@ -834,6 +820,33 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
}
/**
+ * batadv_hardif_cnt() - get number of interfaces enslaved to soft interface
+ * @soft_iface: soft interface to check
+ *
+ * This function is only using RCU for locking - the result can therefore be
+ * off when another functions is modifying the list at the same time. The
+ * caller can use the rtnl_lock to make sure that the count is accurate.
+ *
+ * Return: number of connected/enslaved hard interfaces
+ */
+static size_t batadv_hardif_cnt(const struct net_device *soft_iface)
+{
+ struct batadv_hard_iface *hard_iface;
+ size_t count = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+ if (hard_iface->soft_iface != soft_iface)
+ continue;
+
+ count++;
+ }
+ rcu_read_unlock();
+
+ return count;
+}
+
+/**
* batadv_hardif_disable_interface() - Remove hard interface from soft interface
* @hard_iface: hard interface to be removed
* @autodel: whether to delete soft interface when it doesn't contain any other
@@ -855,9 +868,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
dev_remove_pack(&hard_iface->batman_adv_ptype);
batadv_hardif_put(hard_iface);
- bat_priv->num_ifaces--;
- batadv_orig_hash_del_if(hard_iface, bat_priv->num_ifaces);
-
primary_if = batadv_primary_if_get_selected(bat_priv);
if (hard_iface == primary_if) {
struct batadv_hard_iface *new_if;
@@ -881,7 +891,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface);
/* nobody uses this interface anymore */
- if (bat_priv->num_ifaces == 0) {
+ if (batadv_hardif_cnt(hard_iface->soft_iface) <= 1) {
batadv_gw_check_client_stop(bat_priv);
if (autodel == BATADV_IF_CLEANUP_AUTO)
@@ -917,7 +927,6 @@ batadv_hardif_add_interface(struct net_device *net_dev)
if (ret)
goto free_if;
- hard_iface->if_num = 0;
hard_iface->net_dev = net_dev;
hard_iface->soft_iface = NULL;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 1d295da3e342..56a981af5c92 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -904,9 +904,6 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
batadv_frag_purge_orig(orig_node, NULL);
- if (orig_node->bat_priv->algo_ops->orig.free)
- orig_node->bat_priv->algo_ops->orig.free(orig_node);
-
kfree(orig_node->tt_buff);
kfree(orig_node);
}
@@ -1555,107 +1552,3 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb)
return ret;
}
-
-/**
- * batadv_orig_hash_add_if() - Add interface to originators in orig_hash
- * @hard_iface: hard interface to add (already slave of the soft interface)
- * @max_if_num: new number of interfaces
- *
- * Return: 0 on success or negative error number in case of failure
- */
-int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
- unsigned int max_if_num)
-{
- struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
- struct batadv_algo_ops *bao = bat_priv->algo_ops;
- struct batadv_hashtable *hash = bat_priv->orig_hash;
- struct hlist_head *head;
- struct batadv_orig_node *orig_node;
- u32 i;
- int ret;
-
- /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
- * if_num
- */
- for (i = 0; i < hash->size; i++) {
- head = &hash->table[i];
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
- ret = 0;
- if (bao->orig.add_if)
- ret = bao->orig.add_if(orig_node, max_if_num);
- if (ret == -ENOMEM)
- goto err;
- }
- rcu_read_unlock();
- }
-
- return 0;
-
-err:
- rcu_read_unlock();
- return -ENOMEM;
-}
-
-/**
- * batadv_orig_hash_del_if() - Remove interface from originators in orig_hash
- * @hard_iface: hard interface to remove (still slave of the soft interface)
- * @max_if_num: new number of interfaces
- *
- * Return: 0 on success or negative error number in case of failure
- */
-int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
- unsigned int max_if_num)
-{
- struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
- struct batadv_hashtable *hash = bat_priv->orig_hash;
- struct hlist_head *head;
- struct batadv_hard_iface *hard_iface_tmp;
- struct batadv_orig_node *orig_node;
- struct batadv_algo_ops *bao = bat_priv->algo_ops;
- u32 i;
- int ret;
-
- /* resize all orig nodes because orig_node->bcast_own(_sum) depend on
- * if_num
- */
- for (i = 0; i < hash->size; i++) {
- head = &hash->table[i];
-
- rcu_read_lock();
- hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
- ret = 0;
- if (bao->orig.del_if)
- ret = bao->orig.del_if(orig_node, max_if_num,
- hard_iface->if_num);
- if (ret == -ENOMEM)
- goto err;
- }
- rcu_read_unlock();
- }
-
- /* renumber remaining batman interfaces _inside_ of orig_hash_lock */
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface_tmp, &batadv_hardif_list, list) {
- if (hard_iface_tmp->if_status == BATADV_IF_NOT_IN_USE)
- continue;
-
- if (hard_iface == hard_iface_tmp)
- continue;
-
- if (hard_iface->soft_iface != hard_iface_tmp->soft_iface)
- continue;
-
- if (hard_iface_tmp->if_num > hard_iface->if_num)
- hard_iface_tmp->if_num--;
- }
- rcu_read_unlock();
-
- hard_iface->if_num = -1;
- return 0;
-
-err:
- rcu_read_unlock();
- return -ENOMEM;
-}
diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h
index 3b3f59b881e1..a8b4c7b667ec 100644
--- a/net/batman-adv/originator.h
+++ b/net/batman-adv/originator.h
@@ -72,10 +72,6 @@ void batadv_orig_ifinfo_put(struct batadv_orig_ifinfo *orig_ifinfo);
int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb);
int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
-int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
- unsigned int max_if_num);
-int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
- unsigned int max_if_num);
struct batadv_orig_node_vlan *
batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
unsigned short vid);
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 1485263a348b..e121c59fc1fa 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -833,7 +833,6 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->frag_seqno, random_seqno);
bat_priv->primary_if = NULL;
- bat_priv->num_ifaces = 0;
batadv_nc_init_bat_priv(bat_priv);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 343d304851a5..45b5592de816 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -167,9 +167,6 @@ struct batadv_hard_iface {
/** @list: list node for batadv_hardif_list */
struct list_head list;
- /** @if_num: identificator of the interface */
- unsigned int if_num;
-
/** @if_status: status of the interface for batman-adv */
char if_status;
@@ -233,6 +230,20 @@ struct batadv_hard_iface {
};
/**
+ * struct batadv_orig_ifinfo - B.A.T.M.A.N. IV private orig_ifinfo members
+ */
+struct batadv_orig_ifinfo_bat_iv {
+ /**
+ * @bcast_own: bitfield which counts the number of our OGMs this
+ * orig_node rebroadcasted "back" to us (relative to last_real_seqno)
+ */
+ DECLARE_BITMAP(bcast_own, BATADV_TQ_LOCAL_WINDOW_SIZE);
+
+ /** @bcast_own_sum: sum of bcast_own */
+ u8 bcast_own_sum;
+};
+
+/**
* struct batadv_orig_ifinfo - originator info per outgoing interface
*/
struct batadv_orig_ifinfo {
@@ -257,6 +268,9 @@ struct batadv_orig_ifinfo {
/** @batman_seqno_reset: time when the batman seqno window was reset */
unsigned long batman_seqno_reset;
+ /** @bat_iv: B.A.T.M.A.N. IV private structure */
+ struct batadv_orig_ifinfo_bat_iv bat_iv;
+
/** @refcount: number of contexts the object is used */
struct kref refcount;
@@ -339,19 +353,10 @@ struct batadv_orig_node_vlan {
*/
struct batadv_orig_bat_iv {
/**
- * @bcast_own: set of bitfields (one per hard-interface) where each one
- * counts the number of our OGMs this orig_node rebroadcasted "back" to
- * us (relative to last_real_seqno). Every bitfield is
- * BATADV_TQ_LOCAL_WINDOW_SIZE bits long.
- */
- unsigned long *bcast_own;
-
- /** @bcast_own_sum: sum of bcast_own */
- u8 *bcast_own_sum;
-
- /**
- * @ogm_cnt_lock: lock protecting bcast_own, bcast_own_sum,
- * neigh_node->bat_iv.real_bits & neigh_node->bat_iv.real_packet_count
+ * @ogm_cnt_lock: lock protecting &batadv_orig_ifinfo_bat_iv.bcast_own,
+ * &batadv_orig_ifinfo_bat_iv.bcast_own_sum,
+ * &batadv_neigh_ifinfo_bat_iv.bat_iv.real_bits and
+ * &batadv_neigh_ifinfo_bat_iv.real_packet_count
*/
spinlock_t ogm_cnt_lock;
};
@@ -1597,9 +1602,6 @@ struct batadv_priv {
/** @batman_queue_left: number of remaining OGM packet slots */
atomic_t batman_queue_left;
- /** @num_ifaces: number of interfaces assigned to this mesh interface */
- unsigned int num_ifaces;
-
/** @mesh_obj: kobject for sysfs mesh subdirectory */
struct kobject *mesh_obj;
@@ -2179,28 +2181,6 @@ struct batadv_algo_neigh_ops {
* struct batadv_algo_orig_ops - mesh algorithm callbacks (originator specific)
*/
struct batadv_algo_orig_ops {
- /**
- * @free: free the resources allocated by the routing algorithm for an
- * orig_node object (optional)
- */
- void (*free)(struct batadv_orig_node *orig_node);
-
- /**
- * @add_if: ask the routing algorithm to apply the needed changes to the
- * orig_node due to a new hard-interface being added into the mesh
- * (optional)
- */
- int (*add_if)(struct batadv_orig_node *orig_node,
- unsigned int max_if_num);
-
- /**
- * @del_if: ask the routing algorithm to apply the needed changes to the
- * orig_node due to an hard-interface being removed from the mesh
- * (optional)
- */
- int (*del_if)(struct batadv_orig_node *orig_node,
- unsigned int max_if_num, unsigned int del_if_num);
-
#ifdef CONFIG_BATMAN_ADV_DEBUGFS
/** @print: print the originator table (optional) */
void (*print)(struct batadv_priv *priv, struct seq_file *seq,
--
2.11.0
^ permalink raw reply related
* [PATCH 3/5] batman-adv: Provide debug messages as trace events
From: Simon Wunderlich @ 2018-09-19 12:32 UTC (permalink / raw)
To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20180919123238.23742-1-sw@simonwunderlich.de>
From: Sven Eckelmann <sven@narfation.org>
A private debug logging infrastructure is currently provided via
$debug_fs/batman_adv/*/log when CONFIG_BATMAN_ADV_DEBUG is enabled. This is
not well integrated in the rest of the tracing infrastructure of the
kernel.
Other components (like mac80211 or ath10k) allow to gather the debug
messages using generic trace events which are better integrated. This makes
it possible to interact with them using the existing userspace tools.
The tracepoint batadv:batadv_dbg will now be available when
CONFIG_BATMAN_ADV_DEBUG and CONFIG_BATMAN_ADV_TRACING is activated. The log
level mask is still used for filtering as usual.
A full system trace for offline parsing can be created (and read) using:
$ batctl ll all
$ trace-cmd record -e batadv:batadv_dbg
$ trace-cmd report
The same can also be done without recording to a file
$ batctl ll all
$ trace-cmd stream -e batadv:batadv_dbg
The trace infrastructure is especially helpful when tracing processes:
$ batctl ll all
$ ./tools/perf/perf trace --event "batadv:*" batctl p 10.204.32.1
0.000 batadv:batadv_dbg:batman_adv bat0 Parsing outgoing ARP REQUEST
0.045 batadv:batadv_dbg:batman_adv bat0 ARP MSG = [src: a2:64:14:53:f8:22-10.204.32.185 dst: 00:00:00:00:00:00-10.204.32.1]
0.067 batadv:batadv_dbg:batman_adv bat0 Entry updated: 10.204.32.185 a2:64:14:53:f8:22 (vid: -1)
0.099 batadv:batadv_dbg:batman_adv bat0 batadv_dat_select_candidates(): IP=10.204.32.1 hash(IP)=48902
0.757 batadv:batadv_dbg:batman_adv bat0 dat_select_candidates() 0: selected fe:2c:91:68:29:2b addr=48977 dist=65460
1.178 batadv:batadv_dbg:batman_adv bat0 dat_select_candidates() 1: selected fe:81:ab:c5:e3:03 addr=49181 dist=65256
1.809 batadv:batadv_dbg:batman_adv bat0 dat_select_candidates() 2: selected 66:25:a7:48:37:fb addr=49328 dist=65109
1.828 batadv:batadv_dbg:batman_adv bat0 DHT_SEND for 10.204.32.1
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/Kconfig | 11 +++++++
net/batman-adv/Makefile | 3 ++
net/batman-adv/log.c | 18 ++++++++----
net/batman-adv/trace.c | 22 ++++++++++++++
net/batman-adv/trace.h | 78 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 127 insertions(+), 5 deletions(-)
create mode 100644 net/batman-adv/trace.c
create mode 100644 net/batman-adv/trace.h
diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 361116f77cb9..f75816f58107 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -106,3 +106,14 @@ config BATMAN_ADV_DEBUG
say N here. This enables compilation of support for
outputting debugging information to the kernel log. The
output is controlled via the module parameter debug.
+
+config BATMAN_ADV_TRACING
+ bool "B.A.T.M.A.N. tracing support"
+ depends on BATMAN_ADV
+ depends on EVENT_TRACING
+ help
+ This is an option for use by developers; most people should
+ say N here. Select this option to gather traces like the debug
+ messages using the generic tracing infrastructure of the kernel.
+ BATMAN_ADV_DEBUG must also be selected to get trace events for
+ batadv_dbg.
diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile
index b97ba6fb8353..9b58160fe485 100644
--- a/net/batman-adv/Makefile
+++ b/net/batman-adv/Makefile
@@ -42,6 +42,9 @@ batman-adv-y += routing.o
batman-adv-y += send.o
batman-adv-y += soft-interface.o
batman-adv-y += sysfs.o
+batman-adv-$(CONFIG_BATMAN_ADV_TRACING) += trace.o
batman-adv-y += tp_meter.o
batman-adv-y += translation-table.o
batman-adv-y += tvlv.o
+
+CFLAGS_trace.o := -I$(src)
diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c
index 1032d84e21ae..6beb5f067810 100644
--- a/net/batman-adv/log.c
+++ b/net/batman-adv/log.c
@@ -41,6 +41,7 @@
#include <stdarg.h>
#include "debugfs.h"
+#include "trace.h"
#define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
@@ -100,13 +101,19 @@ static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
*/
int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
- char tmp_log_buf[256];
va_start(args, fmt);
- vscnprintf(tmp_log_buf, sizeof(tmp_log_buf), fmt, args);
- batadv_fdebug_log(bat_priv->debug_log, "[%10u] %s",
- jiffies_to_msecs(jiffies), tmp_log_buf);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ batadv_fdebug_log(bat_priv->debug_log, "[%10u] %pV",
+ jiffies_to_msecs(jiffies), &vaf);
+
+ trace_batadv_dbg(bat_priv, &vaf);
+
va_end(args);
return 0;
@@ -117,7 +124,8 @@ static int batadv_log_open(struct inode *inode, struct file *file)
if (!try_module_get(THIS_MODULE))
return -EBUSY;
- batadv_debugfs_deprecated(file, "");
+ batadv_debugfs_deprecated(file,
+ "Use tracepoint batadv:batadv_dbg instead\n");
nonseekable_open(inode, file);
file->private_data = inode->i_private;
diff --git a/net/batman-adv/trace.c b/net/batman-adv/trace.c
new file mode 100644
index 000000000000..3d57f9981f25
--- /dev/null
+++ b/net/batman-adv/trace.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2010-2018 B.A.T.M.A.N. contributors:
+ *
+ * Sven Eckelmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/net/batman-adv/trace.h b/net/batman-adv/trace.h
new file mode 100644
index 000000000000..3acda26a30ca
--- /dev/null
+++ b/net/batman-adv/trace.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2010-2018 B.A.T.M.A.N. contributors:
+ *
+ * Sven Eckelmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined(_NET_BATMAN_ADV_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _NET_BATMAN_ADV_TRACE_H_
+
+#include "main.h"
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM batadv
+
+/* provide dummy function when tracing is disabled */
+#if !defined(CONFIG_BATMAN_ADV_TRACING)
+
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+ static inline void trace_ ## name(proto) {}
+
+#endif /* CONFIG_BATMAN_ADV_TRACING */
+
+#define BATADV_MAX_MSG_LEN 256
+
+TRACE_EVENT(batadv_dbg,
+
+ TP_PROTO(struct batadv_priv *bat_priv,
+ struct va_format *vaf),
+
+ TP_ARGS(bat_priv, vaf),
+
+ TP_STRUCT__entry(
+ __string(device, bat_priv->soft_iface->name)
+ __string(driver, KBUILD_MODNAME)
+ __dynamic_array(char, msg, BATADV_MAX_MSG_LEN)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, bat_priv->soft_iface->name);
+ __assign_str(driver, KBUILD_MODNAME);
+ WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+ BATADV_MAX_MSG_LEN,
+ vaf->fmt,
+ *vaf->va) >= BATADV_MAX_MSG_LEN);
+ ),
+
+ TP_printk(
+ "%s %s %s",
+ __get_str(driver),
+ __get_str(device),
+ __get_str(msg)
+ )
+);
+
+#endif /* _NET_BATMAN_ADV_TRACE_H_ || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.11.0
^ permalink raw reply related
* [PATCH 04/21] soc/fsl/qman-portal: map CENA area in the iommu
From: laurentiu.tudor @ 2018-09-19 12:35 UTC (permalink / raw)
To: devicetree, netdev, linux-kernel, linux-arm-kernel
Cc: roy.pledge, madalin.bucur, davem, shawnguo, leoyang.li,
Laurentiu Tudor
In-Reply-To: <20180919123613.15092-1-laurentiu.tudor@nxp.com>
From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
Add a one-to-one iommu mapping for qman portal CENA register area.
This is required for QMAN stashing to work without faults behind
an iommu.
Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
---
drivers/soc/fsl/qbman/qman_portal.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c
index a120002b630e..012bb95e87e1 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -29,6 +29,7 @@
*/
#include "qman_priv.h"
+#include <linux/iommu.h>
struct qman_portal *qman_dma_portal;
EXPORT_SYMBOL(qman_dma_portal);
@@ -222,6 +223,7 @@ static int qman_portal_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
+ struct iommu_domain *domain;
struct qm_portal_config *pcfg;
struct resource *addr_phys[2];
int irq, cpu, err;
@@ -276,6 +278,21 @@ static int qman_portal_probe(struct platform_device *pdev)
goto err_ioremap2;
}
+ /* Create an 1-to-1 iommu mapping for cena portal area */
+ domain = iommu_get_domain_for_dev(dev);
+ if (domain) {
+ /*
+ * Note: not mapping this as cacheable triggers the infamous
+ * QMan CIDE error.
+ */
+ err = iommu_map(iommu_get_domain_for_dev(dev),
+ addr_phys[0]->start, addr_phys[0]->start,
+ resource_size(addr_phys[0]),
+ IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE);
+ if (err)
+ dev_warn(dev, "failed to iommu_map() %d\n", err);
+ }
+
pcfg->pools = qm_get_pools_sdqcr();
spin_lock(&qman_lock);
--
2.17.1
^ permalink raw reply related
* [PATCH 11/21] dpaa_eth: defer probing after qbman
From: laurentiu.tudor @ 2018-09-19 12:36 UTC (permalink / raw)
To: devicetree, netdev, linux-kernel, linux-arm-kernel
Cc: roy.pledge, madalin.bucur, davem, shawnguo, leoyang.li,
Laurentiu Tudor
In-Reply-To: <20180919123613.15092-1-laurentiu.tudor@nxp.com>
From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
Enabling SMMU altered the order of device probing causing the dpaa1
ethernet driver to get probed before qbman and causing a boot crash.
Add predictability in the probing order by deferring the ethernet
driver probe after qbman and portals by using the recently introduced
qbman APIs.
Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
---
.../net/ethernet/freescale/dpaa/dpaa_eth.c | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index a5131a510e8b..6ca3fdbef580 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -2765,6 +2765,37 @@ static int dpaa_eth_probe(struct platform_device *pdev)
int err = 0, i, channel;
struct device *dev;
+ err = bman_is_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev, "failing probe due to bman probe error\n");
+ return -ENODEV;
+ }
+ err = qman_is_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev, "failing probe due to qman probe error\n");
+ return -ENODEV;
+ }
+ err = bman_portals_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failing probe due to bman portals probe error\n");
+ return -ENODEV;
+ }
+ err = qman_portals_probed();
+ if (!err)
+ return -EPROBE_DEFER;
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "failing probe due to qman portals probe error\n");
+ return -ENODEV;
+ }
+
/* device used for DMA mapping */
dev = pdev->dev.parent;
err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40));
--
2.17.1
^ permalink raw reply related
* [PATCH 14/21] dpaa_eth: fix iova handling for sg frames
From: laurentiu.tudor @ 2018-09-19 12:36 UTC (permalink / raw)
To: devicetree, netdev, linux-kernel, linux-arm-kernel
Cc: roy.pledge, madalin.bucur, davem, shawnguo, leoyang.li,
Laurentiu Tudor
In-Reply-To: <20180919123613.15092-1-laurentiu.tudor@nxp.com>
From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
The driver relies on the no longer valid assumption that dma addresses
(iovas) are identical to physical addressees and uses phys_to_virt() to
make iova -> vaddr conversions. Fix this also for scatter-gather frames
using the iova -> phys conversion function added in the previous patch.
While at it, clean-up a redundant dpaa_bpid2pool() and pass the bp
as parameter.
Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
---
.../net/ethernet/freescale/dpaa/dpaa_eth.c | 41 +++++++++++--------
1 file changed, 24 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
index e9e081c3f8cc..8db861f281a0 100644
--- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
+++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
@@ -1646,14 +1646,17 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) {
nr_frags = skb_shinfo(skb)->nr_frags;
- dma_unmap_single(dev, addr,
- qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
- dma_dir);
/* The sgt buffer has been allocated with netdev_alloc_frag(),
* it's from lowmem.
*/
- sgt = phys_to_virt(addr + qm_fd_get_offset(fd));
+ sgt = phys_to_virt(dpaa_iova_to_phys(dev,
+ addr +
+ qm_fd_get_offset(fd)));
+
+ dma_unmap_single(dev, addr,
+ qm_fd_get_offset(fd) + DPAA_SGT_SIZE,
+ dma_dir);
/* sgt[0] is from lowmem, was dma_map_single()-ed */
dma_unmap_single(dev, qm_sg_addr(&sgt[0]),
@@ -1668,7 +1671,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv,
}
/* Free the page frag that we allocated on Tx */
- skb_free_frag(phys_to_virt(addr));
+ skb_free_frag(skbh);
} else {
dma_unmap_single(dev, addr,
skb_tail_pointer(skb) - (u8 *)skbh, dma_dir);
@@ -1729,14 +1732,14 @@ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv,
* The page fragment holding the S/G Table is recycled here.
*/
static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
- const struct qm_fd *fd)
+ const struct qm_fd *fd,
+ struct dpaa_bp *dpaa_bp,
+ void *vaddr)
{
ssize_t fd_off = qm_fd_get_offset(fd);
- dma_addr_t addr = qm_fd_addr(fd);
const struct qm_sg_entry *sgt;
struct page *page, *head_page;
- struct dpaa_bp *dpaa_bp;
- void *vaddr, *sg_vaddr;
+ void *sg_vaddr;
int frag_off, frag_len;
struct sk_buff *skb;
dma_addr_t sg_addr;
@@ -1745,7 +1748,6 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
int *count_ptr;
int i;
- vaddr = phys_to_virt(addr);
WARN_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES));
/* Iterate through the SGT entries and add data buffers to the skb */
@@ -1756,14 +1758,18 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
WARN_ON(qm_sg_entry_is_ext(&sgt[i]));
sg_addr = qm_sg_addr(&sgt[i]);
- sg_vaddr = phys_to_virt(sg_addr);
- WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
- SMP_CACHE_BYTES));
/* We may use multiple Rx pools */
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
- if (!dpaa_bp)
+ if (!dpaa_bp) {
+ pr_info("%s: fail to get dpaa_bp for sg bpid %d\n",
+ __func__, sgt[i].bpid);
goto free_buffers;
+ }
+ sg_vaddr = phys_to_virt(dpaa_iova_to_phys(dpaa_bp->dev,
+ sg_addr));
+ WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
+ SMP_CACHE_BYTES));
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size,
@@ -1835,10 +1841,11 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
/* free all the SG entries */
for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) {
sg_addr = qm_sg_addr(&sgt[i]);
- sg_vaddr = phys_to_virt(sg_addr);
- skb_free_frag(sg_vaddr);
dpaa_bp = dpaa_bpid2pool(sgt[i].bpid);
if (dpaa_bp) {
+ sg_addr = dpaa_iova_to_phys(dpaa_bp->dev, sg_addr);
+ sg_vaddr = phys_to_virt(sg_addr);
+ skb_free_frag(sg_vaddr);
count_ptr = this_cpu_ptr(dpaa_bp->percpu_count);
(*count_ptr)--;
}
@@ -2324,7 +2331,7 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
if (likely(fd_format == qm_fd_contig))
skb = contig_fd_to_skb(priv, fd, dpaa_bp, vaddr);
else
- skb = sg_fd_to_skb(priv, fd);
+ skb = sg_fd_to_skb(priv, fd, dpaa_bp, vaddr);
if (!skb)
return qman_cb_dqrr_consume;
--
2.17.1
^ permalink raw reply related
* [PATCH 20/21] arm64: dts: ls104x: add iommu-map to pci controllers
From: laurentiu.tudor @ 2018-09-19 12:36 UTC (permalink / raw)
To: devicetree, netdev, linux-kernel, linux-arm-kernel
Cc: roy.pledge, madalin.bucur, davem, shawnguo, leoyang.li,
Laurentiu Tudor
In-Reply-To: <20180919123613.15092-1-laurentiu.tudor@nxp.com>
From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
The pci controllers are also behind the smmu so add the iommu-map
property to reflect this. The bootloader needs to patch the stream id
ranges to some sane values.
Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 +++
2 files changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
index 48091409c472..3b7b2e60bd9a 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
@@ -716,6 +716,7 @@
#size-cells = <2>;
device_type = "pci";
dma-coherent;
+ iommu-map = <0 &mmu 0 1>;
num-lanes = <4>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -741,6 +742,7 @@
#size-cells = <2>;
device_type = "pci";
dma-coherent;
+ iommu-map = <0 &mmu 0 1>;
num-lanes = <2>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -766,6 +768,7 @@
#size-cells = <2>;
device_type = "pci";
dma-coherent;
+ iommu-map = <0 &mmu 0 1>;
num-lanes = <2>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 40484f6f6d42..890d1565791f 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -685,6 +685,7 @@
#size-cells = <2>;
device_type = "pci";
dma-coherent;
+ iommu-map = <0 &mmu 0 1>;
num-lanes = <4>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -710,6 +711,7 @@
#size-cells = <2>;
device_type = "pci";
dma-coherent;
+ iommu-map = <0 &mmu 0 1>;
num-lanes = <2>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */
@@ -735,6 +737,7 @@
#size-cells = <2>;
device_type = "pci";
dma-coherent;
+ iommu-map = <0 &mmu 0 1>;
num-lanes = <2>;
bus-range = <0x0 0xff>;
ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */
--
2.17.1
^ permalink raw reply related
* [PATCH net-next] ipv6: Allow the l3mdev to be a loopback
From: Mike Manning @ 2018-09-19 11:34 UTC (permalink / raw)
To: netdev
There is no way currently for an IPv6 client connect using a loopback
address in a VRF, whereas for IPv4 the loopback address can be added:
$ sudo ip addr add dev vrfred 127.0.0.1/8
$ sudo ip -6 addr add ::1/128 dev vrfred
RTNETLINK answers: Cannot assign requested address
So allow ::1 to be configured on an L3 master device. In order for
this to be usable ip_route_output_flags needs to not consider ::1 to
be a link scope address (since oif == l3mdev and so it would be
dropped), and ipv6_rcv needs to consider the l3mdev to be a loopback
device so that it doesn't drop the packets.
Signed-off-by: Robert Shearman <rshearma@vyatta.att-mail.com>
---
net/ipv6/addrconf.c | 1 +
net/ipv6/ip6_input.c | 3 ++-
net/ipv6/route.c | 3 ++-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d4733160e6b7..bfe3ec7ecb14 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -997,6 +997,7 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
if (addr_type == IPV6_ADDR_ANY ||
addr_type & IPV6_ADDR_MULTICAST ||
(!(idev->dev->flags & IFF_LOOPBACK) &&
+ !netif_is_l3_master(idev->dev) &&
addr_type & IPV6_ADDR_LOOPBACK))
return ERR_PTR(-EADDRNOTAVAIL);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6242682be876..96577e742afd 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -178,7 +178,8 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
*/
if ((ipv6_addr_loopback(&hdr->saddr) ||
ipv6_addr_loopback(&hdr->daddr)) &&
- !(dev->flags & IFF_LOOPBACK))
+ !(dev->flags & IFF_LOOPBACK) &&
+ !netif_is_l3_master(dev))
goto err;
/* RFC4291 Errata ID: 3480
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 0fa62acc923c..f36ee8a3314f 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2098,7 +2098,8 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
{
bool any_src;
- if (rt6_need_strict(&fl6->daddr)) {
+ if (ipv6_addr_type(&fl6->daddr) &
+ (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
struct dst_entry *dst;
dst = l3mdev_link_scope_lookup(net, fl6);
--
2.11.0
^ permalink raw reply related
* [PATCH net] ip6_tunnel: be careful when accessing the inner header
From: Paolo Abeni @ 2018-09-19 13:02 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Alexander Potapenko
the ip6 tunnel xmit ndo assumes that the processed skb always
contains an ip[v6] header, but syzbot has found a way to send
frames that fall short of this assumption, leading to the following splat:
BUG: KMSAN: uninit-value in ip6ip6_tnl_xmit net/ipv6/ip6_tunnel.c:1307
[inline]
BUG: KMSAN: uninit-value in ip6_tnl_start_xmit+0x7d2/0x1ef0
net/ipv6/ip6_tunnel.c:1390
CPU: 0 PID: 4504 Comm: syz-executor558 Not tainted 4.16.0+ #87
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:17 [inline]
dump_stack+0x185/0x1d0 lib/dump_stack.c:53
kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067
__msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:683
ip6ip6_tnl_xmit net/ipv6/ip6_tunnel.c:1307 [inline]
ip6_tnl_start_xmit+0x7d2/0x1ef0 net/ipv6/ip6_tunnel.c:1390
__netdev_start_xmit include/linux/netdevice.h:4066 [inline]
netdev_start_xmit include/linux/netdevice.h:4075 [inline]
xmit_one net/core/dev.c:3026 [inline]
dev_hard_start_xmit+0x5f1/0xc70 net/core/dev.c:3042
__dev_queue_xmit+0x27ee/0x3520 net/core/dev.c:3557
dev_queue_xmit+0x4b/0x60 net/core/dev.c:3590
packet_snd net/packet/af_packet.c:2944 [inline]
packet_sendmsg+0x7c70/0x8a30 net/packet/af_packet.c:2969
sock_sendmsg_nosec net/socket.c:630 [inline]
sock_sendmsg net/socket.c:640 [inline]
___sys_sendmsg+0xec0/0x1310 net/socket.c:2046
__sys_sendmmsg+0x42d/0x800 net/socket.c:2136
SYSC_sendmmsg+0xc4/0x110 net/socket.c:2167
SyS_sendmmsg+0x63/0x90 net/socket.c:2162
do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287
entry_SYSCALL_64_after_hwframe+0x3d/0xa2
RIP: 0033:0x441819
RSP: 002b:00007ffe58ee8268 EFLAGS: 00000213 ORIG_RAX: 0000000000000133
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000441819
RDX: 0000000000000002 RSI: 0000000020000100 RDI: 0000000000000003
RBP: 00000000006cd018 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000213 R12: 0000000000402510
R13: 00000000004025a0 R14: 0000000000000000 R15: 0000000000000000
Uninit was created at:
kmsan_save_stack_with_flags mm/kmsan/kmsan.c:278 [inline]
kmsan_internal_poison_shadow+0xb8/0x1b0 mm/kmsan/kmsan.c:188
kmsan_kmalloc+0x94/0x100 mm/kmsan/kmsan.c:314
kmsan_slab_alloc+0x11/0x20 mm/kmsan/kmsan.c:321
slab_post_alloc_hook mm/slab.h:445 [inline]
slab_alloc_node mm/slub.c:2737 [inline]
__kmalloc_node_track_caller+0xaed/0x11c0 mm/slub.c:4369
__kmalloc_reserve net/core/skbuff.c:138 [inline]
__alloc_skb+0x2cf/0x9f0 net/core/skbuff.c:206
alloc_skb include/linux/skbuff.h:984 [inline]
alloc_skb_with_frags+0x1d4/0xb20 net/core/skbuff.c:5234
sock_alloc_send_pskb+0xb56/0x1190 net/core/sock.c:2085
packet_alloc_skb net/packet/af_packet.c:2803 [inline]
packet_snd net/packet/af_packet.c:2894 [inline]
packet_sendmsg+0x6454/0x8a30 net/packet/af_packet.c:2969
sock_sendmsg_nosec net/socket.c:630 [inline]
sock_sendmsg net/socket.c:640 [inline]
___sys_sendmsg+0xec0/0x1310 net/socket.c:2046
__sys_sendmmsg+0x42d/0x800 net/socket.c:2136
SYSC_sendmmsg+0xc4/0x110 net/socket.c:2167
SyS_sendmmsg+0x63/0x90 net/socket.c:2162
do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287
entry_SYSCALL_64_after_hwframe+0x3d/0xa2
This change addresses the issue adding the needed check before
accessing the inner header.
The ipv4 side of the issue is apparently there since the ipv4 over ipv6
initial support, and the ipv6 side predates git history.
Fixes: c4d3efafcc93 ("[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.")
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Reported-by: syzbot+3fde91d4d394747d6db4@syzkaller.appspotmail.com
Tested-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
net/ipv6/ip6_tunnel.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 419960b0ba16..a0b6932c3afd 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1234,7 +1234,7 @@ static inline int
ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- const struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph;
int encap_limit = -1;
struct flowi6 fl6;
__u8 dsfield;
@@ -1242,6 +1242,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
u8 tproto;
int err;
+ /* ensure we can access the full inner ip header */
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ return -1;
+
+ iph = ip_hdr(skb);
memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
tproto = READ_ONCE(t->parms.proto);
@@ -1306,7 +1311,7 @@ static inline int
ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
- struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ struct ipv6hdr *ipv6h;
int encap_limit = -1;
__u16 offset;
struct flowi6 fl6;
@@ -1315,6 +1320,10 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
u8 tproto;
int err;
+ if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+ return -1;
+
+ ipv6h = ipv6_hdr(skb);
tproto = READ_ONCE(t->parms.proto);
if ((tproto != IPPROTO_IPV6 && tproto != 0) ||
ip6_tnl_addr_conflict(t, ipv6h))
--
2.17.1
^ permalink raw reply related
* Is it possible to get Rx timestamps in skb->tstamp?
From: David Howells @ 2018-09-19 13:03 UTC (permalink / raw)
To: netdev; +Cc: dhowells
Hi,
Is it possible to tell a UDP socket that you'd like it to put reception
timestamps in skb->tstamp?
For some reason, I seem to remember that the kernel used to put something in
there - and AF_RXRPC makes use of it.
David
^ permalink raw reply
* Re: Is it possible to get Rx timestamps in skb->tstamp?
From: Toke Høiland-Jørgensen @ 2018-09-19 13:16 UTC (permalink / raw)
To: David Howells, netdev; +Cc: dhowells
In-Reply-To: <9873.1537362199@warthog.procyon.org.uk>
David Howells <dhowells@redhat.com> writes:
> Hi,
>
> Is it possible to tell a UDP socket that you'd like it to put
> reception timestamps in skb->tstamp?
I think you probably want SO_TIMESTAMP*?
See https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/networking/timestamping.txt
-Toke
^ permalink raw reply
* [PATCH net-next] ipv6: Allow the l3mdev to be a loopback
From: Mike Manning @ 2018-09-19 12:56 UTC (permalink / raw)
To: netdev; +Cc: Robert Shearman
From: Robert Shearman <rshearma@vyatta.att-mail.com>
There is no way currently for an IPv6 client connect using a loopback
address in a VRF, whereas for IPv4 the loopback address can be added:
$ sudo ip addr add dev vrfred 127.0.0.1/8
$ sudo ip -6 addr add ::1/128 dev vrfred
RTNETLINK answers: Cannot assign requested address
So allow ::1 to be configured on an L3 master device. In order for
this to be usable ip_route_output_flags needs to not consider ::1 to
be a link scope address (since oif == l3mdev and so it would be
dropped), and ipv6_rcv needs to consider the l3mdev to be a loopback
device so that it doesn't drop the packets.
Signed-off-by: Robert Shearman <rshearma@vyatta.att-mail.com>
Signed-off-by: Mike Manning <mmanning@vyatta.att-mail.com>
---
net/ipv6/addrconf.c | 1 +
net/ipv6/ip6_input.c | 3 ++-
net/ipv6/route.c | 3 ++-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d4733160e6b7..bfe3ec7ecb14 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -997,6 +997,7 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
if (addr_type == IPV6_ADDR_ANY ||
addr_type & IPV6_ADDR_MULTICAST ||
(!(idev->dev->flags & IFF_LOOPBACK) &&
+ !netif_is_l3_master(idev->dev) &&
addr_type & IPV6_ADDR_LOOPBACK))
return ERR_PTR(-EADDRNOTAVAIL);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 6242682be876..96577e742afd 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -178,7 +178,8 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
*/
if ((ipv6_addr_loopback(&hdr->saddr) ||
ipv6_addr_loopback(&hdr->daddr)) &&
- !(dev->flags & IFF_LOOPBACK))
+ !(dev->flags & IFF_LOOPBACK) &&
+ !netif_is_l3_master(dev))
goto err;
/* RFC4291 Errata ID: 3480
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 0fa62acc923c..f36ee8a3314f 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2098,7 +2098,8 @@ struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk,
{
bool any_src;
- if (rt6_need_strict(&fl6->daddr)) {
+ if (ipv6_addr_type(&fl6->daddr) &
+ (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)) {
struct dst_entry *dst;
dst = l3mdev_link_scope_lookup(net, fl6);
--
2.11.0
^ permalink raw reply related
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