* [net-next 7/7] ip6tlvs: Validation of TX Destination and Hop-by-Hop options
From: Jeff Kirsher @ 2019-08-22 22:59 UTC (permalink / raw)
To: davem; +Cc: Tom Herbert, netdev, nhorman, sassmann, Andrew Bowers,
Jeff Kirsher
In-Reply-To: <20190822225940.14235-1-jeffrey.t.kirsher@intel.com>
From: Tom Herbert <tom@herbertland.com>
Validate Destination and Hop-by-Hop options. This uses the information
in the TLV parameters table to validate various aspects of both
individual TLVs as well as a list of TLVs in an extension header.
There are two levels of validation that can be performed: simple checks
and deep checks. Simple checks validate only the most basic properties
such as that the TLV list fits into the EH. Deep checks do a fine
grained validation that includes preferred ordering, length limits,
and length alignment.
With proper permissions set in the TLV parameter table, this patch
allows non-privileged users to send TLVs. Given that TLVs are open
ended and potentially a source of DOS attack, deep checks are
performed to limit the format that a non-privileged user can send.
If deep checks are enabled, a canonical format for sending TLVs is
enforced (in adherence with the robustness principle). A TLV must
be well ordered with respect to the preferred order for the TLV.
Each TLV must be aligned as described in the parameter table. Minimal
padding (one padding TLV) is used to align TLVs. The length of the
extension header as well as the count of non-padding TLVs is checked
against max_*_opts_len and max_*_opts_cnt. For individual TLVs, length
limits and length alignment is checked.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/net/ipeh.h | 22 +++
net/ipv6/datagram.c | 51 +++--
net/ipv6/exthdrs_common.c | 382 ++++++++++++++++++++++++++++++++++++++
net/ipv6/ipv6_sockglue.c | 39 ++--
4 files changed, 455 insertions(+), 39 deletions(-)
diff --git a/include/net/ipeh.h b/include/net/ipeh.h
index 8474a43f8a08..e58a0f439581 100644
--- a/include/net/ipeh.h
+++ b/include/net/ipeh.h
@@ -157,6 +157,28 @@ struct ipv6_txoptions *ipeh_renew_options(struct sock *sk,
struct ipv6_txoptions *ipeh_fixup_options(struct ipv6_txoptions *opt_space,
struct ipv6_txoptions *opt);
+int ipeh_opt_validate_tlvs(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ struct ipv6_opt_hdr *opt,
+ unsigned int optname, bool admin,
+ unsigned int max_len, unsigned int max_cnt);
+int ipeh_opt_validate_single_tlv(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ unsigned int optname, const __u8 *tlv,
+ size_t len, bool deleting, bool admin);
+int ipeh_opt_check_perm(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ struct ipv6_txoptions *txopt, int optname, bool admin);
+
+struct ipv6_txoptions *ipeh_txopt_from_opt(struct sock *sk,
+ struct tlv_param_table
+ *tlv_param_table,
+ struct ipv6_txoptions *opt,
+ int optname, char __user *optval,
+ unsigned int optlen,
+ unsigned int max_len,
+ unsigned int max_cnt);
+
/* Generic extension header TLV parser */
enum ipeh_parse_errors {
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 9ab897ded4df..4b8777361fa6 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -837,7 +837,10 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
break;
case IPV6_2292HOPOPTS:
- case IPV6_HOPOPTS:
+ case IPV6_HOPOPTS: {
+ int max_len = net->ipv6.sysctl.max_hbh_opts_len;
+ int max_cnt = net->ipv6.sysctl.max_hbh_opts_cnt;
+
if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
err = -EINVAL;
goto exit_f;
@@ -849,15 +852,24 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
err = -EINVAL;
goto exit_f;
}
- if (!ns_capable(net->user_ns, CAP_NET_RAW)) {
- err = -EPERM;
+
+ err = ipeh_opt_validate_tlvs(net, &ipv6_tlv_param_table,
+ hdr, IPV6_HOPOPTS,
+ ns_capable(net->user_ns,
+ CAP_NET_RAW),
+ max_len, max_cnt);
+ if (err < 0)
goto exit_f;
- }
+
opt->opt_nflen += len;
opt->hopopt = hdr;
break;
+ }
+
+ case IPV6_2292DSTOPTS: {
+ int max_len = net->ipv6.sysctl.max_dst_opts_len;
+ int max_cnt = net->ipv6.sysctl.max_dst_opts_cnt;
- case IPV6_2292DSTOPTS:
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
err = -EINVAL;
goto exit_f;
@@ -869,10 +881,14 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
err = -EINVAL;
goto exit_f;
}
- if (!ns_capable(net->user_ns, CAP_NET_RAW)) {
- err = -EPERM;
+ err = ipeh_opt_validate_tlvs(net, &ipv6_tlv_param_table,
+ hdr, IPV6_DSTOPTS,
+ ns_capable(net->user_ns,
+ CAP_NET_RAW),
+ max_len, max_cnt);
+ if (err < 0)
goto exit_f;
- }
+
if (opt->dst1opt) {
err = -EINVAL;
goto exit_f;
@@ -880,9 +896,13 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
opt->opt_flen += len;
opt->dst1opt = hdr;
break;
+ }
case IPV6_DSTOPTS:
- case IPV6_RTHDRDSTOPTS:
+ case IPV6_RTHDRDSTOPTS: {
+ int max_len = net->ipv6.sysctl.max_dst_opts_len;
+ int max_cnt = net->ipv6.sysctl.max_dst_opts_cnt;
+
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {
err = -EINVAL;
goto exit_f;
@@ -894,10 +914,15 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
err = -EINVAL;
goto exit_f;
}
- if (!ns_capable(net->user_ns, CAP_NET_RAW)) {
- err = -EPERM;
+
+ err = ipeh_opt_validate_tlvs(net, &ipv6_tlv_param_table,
+ hdr, IPV6_DSTOPTS,
+ ns_capable(net->user_ns,
+ CAP_NET_RAW),
+ max_len, max_cnt);
+ if (err < 0)
goto exit_f;
- }
+
if (cmsg->cmsg_type == IPV6_DSTOPTS) {
opt->opt_flen += len;
opt->dst1opt = hdr;
@@ -906,7 +931,7 @@ int ip6_datagram_send_ctl(struct net *net, struct sock *sk,
opt->dst0opt = hdr;
}
break;
-
+ }
case IPV6_2292RTHDR:
case IPV6_RTHDR:
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {
diff --git a/net/ipv6/exthdrs_common.c b/net/ipv6/exthdrs_common.c
index b44c6fd05f92..5df55bd6e032 100644
--- a/net/ipv6/exthdrs_common.c
+++ b/net/ipv6/exthdrs_common.c
@@ -262,6 +262,318 @@ bool ipeh_parse_tlv(unsigned int class,
}
EXPORT_SYMBOL(ipeh_parse_tlv);
+/* TLV validation functions */
+
+/* Validate a single non-padding TLV */
+static int __ipeh_opt_validate_single_tlv(struct net *net, const __u8 *tlv,
+ struct tlv_proc *tproc,
+ unsigned int class, bool *deep_check,
+ bool deleting, bool admin)
+{
+ struct tlv_tx_params *tptx = &tproc->params.t;
+
+ if (tlv[0] < 2) /* Must be non-padding */
+ return -EINVAL;
+
+ /* Check permissions */
+ switch (admin ? tptx->admin_perm : tptx->user_perm) {
+ case IPEH_TLV_PERM_NO_CHECK:
+ /* Allowed with no deep checks */
+ *deep_check = false;
+ return 0;
+ case IPEH_TLV_PERM_WITH_CHECK:
+ /* Allowed with deep checks */
+ *deep_check = true;
+ break;
+ default:
+ /* No permission */
+ return -EPERM;
+ }
+
+ /* Perform deep checks on the TLV */
+
+ /* Check class */
+ if ((tptx->class & class) != class)
+ return -EINVAL;
+
+ /* Don't bother checking lengths when deleting, the TLV is only
+ * needed here for lookup
+ */
+ if (deleting) {
+ /* Don't bother with deep checks when deleting */
+ *deep_check = false;
+ } else {
+ /* Check length */
+ if (tlv[1] < tptx->min_data_len || tlv[1] > tptx->max_data_len)
+ return -EINVAL;
+
+ /* Check length alignment */
+ if ((tlv[1] % (tptx->data_len_mult + 1)) != tptx->data_len_off)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned int optname_to_tlv_class(int optname)
+{
+ switch (optname) {
+ case IPV6_HOPOPTS:
+ return IPEH_TLV_CLASS_FLAG_HOPOPT;
+ case IPV6_RTHDRDSTOPTS:
+ return IPEH_TLV_CLASS_FLAG_RTRDSTOPT;
+ case IPV6_DSTOPTS:
+ return IPEH_TLV_CLASS_FLAG_DSTOPT;
+ default:
+ return -1U;
+ }
+}
+
+static int __ipeh_opt_validate_tlvs(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ struct ipv6_opt_hdr *opt,
+ unsigned int optname, bool deleting,
+ bool admin, unsigned int max_len,
+ unsigned int max_cnt)
+{
+ bool deep_check = !admin, did_deep_check = false;
+ unsigned int opt_len, tlv_len, offset;
+ unsigned int padding = 0, numpad = 0;
+ unsigned short prev_tlv_order = 0;
+ unsigned int class, cnt = 0;
+ struct tlv_tx_params *tptx;
+ int retc, ret = -EINVAL;
+ __u8 *tlv = (__u8 *)opt;
+ struct tlv_proc *tproc;
+
+ opt_len = ipv6_optlen(opt);
+ offset = sizeof(*opt);
+
+ class = optname_to_tlv_class(optname);
+
+ rcu_read_lock();
+
+ while (offset < opt_len) {
+ switch (tlv[offset]) {
+ case IPV6_TLV_PAD1:
+ tlv_len = 1;
+ padding++;
+ numpad++;
+ break;
+ case IPV6_TLV_PADN:
+ if (offset + 1 >= opt_len)
+ goto out;
+
+ tlv_len = tlv[offset + 1] + 2;
+
+ if (offset + tlv_len > opt_len)
+ goto out;
+
+ padding += tlv_len;
+ numpad++;
+ break;
+ default:
+ if (offset + 1 >= opt_len)
+ goto out;
+
+ tlv_len = tlv[offset + 1] + 2;
+
+ if (offset + tlv_len > opt_len)
+ goto out;
+
+ tproc = ipeh_tlv_get_proc(tlv_param_table,
+ &tlv[offset]);
+ tptx = &tproc->params.t;
+
+ retc = __ipeh_opt_validate_single_tlv(net, &tlv[offset],
+ tproc, class,
+ &deep_check,
+ deleting, admin);
+ if (retc < 0) {
+ ret = retc;
+ goto out;
+ }
+
+ if (deep_check) {
+ /* Check for too many options */
+ if (++cnt > max_cnt) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ /* Check order */
+ if (tptx->preferred_order < prev_tlv_order)
+ goto out;
+
+ /* Check alignment */
+ if ((offset % (tptx->align_mult + 1)) !=
+ tptx->align_off)
+ goto out;
+
+ /* Check for right amount of padding */
+ if (numpad > 1 || padding > tptx->align_mult)
+ goto out;
+
+ prev_tlv_order = tptx->preferred_order;
+
+ did_deep_check = true;
+ }
+ padding = 0;
+ numpad = 0;
+ }
+ offset += tlv_len;
+ }
+
+ /* Check trailing padding. Note this covers the case option list
+ * only contains padding.
+ */
+ if (deep_check && (numpad > 1 || padding > 7))
+ goto out;
+
+ /* If we did at least one deep check apply length limit */
+ if (did_deep_check && opt_len > max_len) {
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ /* All good */
+ ret = 0;
+out:
+ rcu_read_unlock();
+
+ return ret;
+}
+
+/**
+ * ipeh_opt_validate_tlvs - Validate TLVs.
+ * @net: Current net
+ * @tlv_param_table: TLV parameter table
+ * @opt: The option header
+ * @optname: IPV6_HOPOPTS, IPV6_RTHDRDSTOPTS, or IPV6_DSTOPTS
+ * @admin: Set for privileged user
+ * @max_len: Maximum length for TLV
+ * @max_cnt: Maximum number of non-padding TLVs
+ *
+ * Description:
+ * Walks the TLVs in a list to verify that the TLV lengths and other
+ * parameters are in bounds for a Destination or Hop-by-Hop option.
+ * Return -EINVAL is there is a problem, zero otherwise.
+ */
+int ipeh_opt_validate_tlvs(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ struct ipv6_opt_hdr *opt, unsigned int optname,
+ bool admin, unsigned int max_len,
+ unsigned int max_cnt)
+{
+ return __ipeh_opt_validate_tlvs(net, tlv_param_table, opt, optname,
+ false, admin, max_len, max_cnt);
+}
+EXPORT_SYMBOL(ipeh_opt_validate_tlvs);
+
+/**
+ * ipeh_opt_validate_single_tlv - Check that a single TLV is valid.
+ * @net: Current net
+ * @tlv_param_table: TLV parameter table
+ * @optname: IPV6_HOPOPTS, IPV6_RTHDRDSTOPTS, or IPV6_DSTOPTS
+ * @tlv: The TLV as array of bytes
+ * @len: Length of buffer holding TLV
+ * @deleting: TLV is being deleted
+ * @admin: Set for privileged user
+ *
+ * Description:
+ * Validates a single TLV. The TLV must be non-padding type. The length
+ * of the TLV (as determined by the second byte that gives length of the
+ * option data) must match @len.
+ */
+int ipeh_opt_validate_single_tlv(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ unsigned int optname, const __u8 *tlv,
+ size_t len, bool deleting, bool admin)
+{
+ struct tlv_proc *tproc;
+ unsigned int class;
+ bool deep_check;
+ int ret = 0;
+
+ class = optname_to_tlv_class(optname);
+
+ if (tlv[0] < 2)
+ return -EINVAL;
+
+ if (len < 2)
+ return -EINVAL;
+
+ if (tlv[1] + 2 != len)
+ return -EINVAL;
+
+ rcu_read_lock();
+
+ tproc = ipeh_tlv_get_proc(tlv_param_table, tlv);
+
+ ret = __ipeh_opt_validate_single_tlv(net, tlv, tproc, class,
+ &deep_check, deleting, admin);
+
+ rcu_read_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL(ipeh_opt_validate_single_tlv);
+
+/**
+ * ipeh_opt_check_perm - Check that current capabilities allows modifying
+ * txopts.
+ * @net: Current net
+ * @tlv_param_table: TLV parameter table
+ * @txopts: TX options from the socket
+ * @optname: IPV6_HOPOPTS, IPV6_RTHDRDSTOPTS, or IPV6_DSTOPTS
+ * @admin: Set for privileged user
+ *
+ * Description:
+ *
+ * Checks whether the permissions of TLV that are set on a socket permit
+ * modificationr.
+ *
+ */
+int ipeh_opt_check_perm(struct net *net,
+ struct tlv_param_table *tlv_param_table,
+ struct ipv6_txoptions *txopt, int optname, bool admin)
+{
+ struct ipv6_opt_hdr *opt;
+ int retv = -EPERM;
+
+ if (!txopt)
+ return 0;
+
+ switch (optname) {
+ case IPV6_HOPOPTS:
+ opt = txopt->hopopt;
+ break;
+ case IPV6_RTHDRDSTOPTS:
+ opt = txopt->dst0opt;
+ break;
+ case IPV6_DSTOPTS:
+ opt = txopt->dst1opt;
+ break;
+ default:
+ goto out;
+ }
+
+ if (!opt) {
+ retv = 0;
+ goto out;
+ }
+
+ /* Just call the validate function on the options as being
+ * deleted.
+ */
+ retv = __ipeh_opt_validate_tlvs(net, tlv_param_table, opt, optname,
+ true, admin, -1U, -1U);
+
+out:
+ return retv;
+}
+EXPORT_SYMBOL(ipeh_opt_check_perm);
+
/* TLV parameter table functions and structures */
/* Default (unset) values for TLV parameters */
@@ -454,6 +766,76 @@ int __ipeh_tlv_unset(struct tlv_param_table *tlv_param_table,
}
EXPORT_SYMBOL(__ipeh_tlv_unset);
+/* Utility function tp create TX options from a setsockopt that is setting
+ * options on a socket.
+ */
+struct ipv6_txoptions *ipeh_txopt_from_opt(struct sock *sk,
+ struct tlv_param_table
+ *tlv_param_table,
+ struct ipv6_txoptions *opt,
+ int optname, char __user *optval,
+ unsigned int optlen,
+ unsigned int max_len,
+ unsigned int max_cnt)
+{
+ struct ipv6_opt_hdr *new = NULL;
+ struct net *net = sock_net(sk);
+ int retv;
+
+ /* remove any sticky options header with a zero option
+ * length, per RFC3542.
+ */
+ if (optlen == 0) {
+ optval = NULL;
+ } else if (!optval) {
+ return ERR_PTR(-EINVAL);
+ } else if (optlen < sizeof(struct ipv6_opt_hdr) ||
+ optlen & 0x7 || optlen > 8 * 255) {
+ return ERR_PTR(-EINVAL);
+ } else {
+ new = memdup_user(optval, optlen);
+ if (IS_ERR(new))
+ return (struct ipv6_txoptions *)new;
+ if (unlikely(ipv6_optlen(new) > optlen)) {
+ kfree(new);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ if (optname != IPV6_RTHDR) {
+ bool cap = ns_capable(net->user_ns, CAP_NET_RAW);
+
+ /* First check if we have permission to delete
+ * the existing options on the socket.
+ */
+ retv = ipeh_opt_check_perm(net, tlv_param_table,
+ opt, optname, cap);
+ if (retv < 0) {
+ kfree(new);
+ return ERR_PTR(retv);
+ }
+
+ /* Check permissions and other validations on new
+ * TLVs
+ */
+ if (new) {
+ retv = ipeh_opt_validate_tlvs(net, tlv_param_table,
+ new, optname, cap,
+ max_len, max_cnt);
+ if (retv < 0) {
+ kfree(new);
+ return ERR_PTR(retv);
+ }
+ }
+ }
+
+ opt = ipeh_renew_options(sk, opt, optname, new);
+ kfree(new);
+
+ return opt;
+}
+EXPORT_SYMBOL(ipeh_txopt_from_opt);
+
const struct nla_policy ipeh_tlv_nl_policy[IPEH_TLV_ATTR_MAX + 1] = {
[IPEH_TLV_ATTR_TYPE] = { .type = NLA_U8, },
[IPEH_TLV_ATTR_ORDER] = { .type = NLA_U16, },
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 8755ecc13d0e..b8e007ca9da9 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -395,40 +395,27 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
case IPV6_RTHDR:
case IPV6_DSTOPTS:
{
+ unsigned int max_len = -1U, max_cnt = -1U;
struct ipv6_txoptions *opt;
- struct ipv6_opt_hdr *new = NULL;
- /* hop-by-hop / destination options are privileged option */
- retv = -EPERM;
- if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
+ switch (optname) {
+ case IPV6_HOPOPTS:
+ max_len = net->ipv6.sysctl.max_hbh_opts_len;
+ max_cnt = net->ipv6.sysctl.max_hbh_opts_cnt;
break;
-
- /* remove any sticky options header with a zero option
- * length, per RFC3542.
- */
- if (optlen == 0)
- optval = NULL;
- else if (!optval)
- goto e_inval;
- else if (optlen < sizeof(struct ipv6_opt_hdr) ||
- optlen & 0x7 || optlen > 8 * 255)
- goto e_inval;
- else {
- new = memdup_user(optval, optlen);
- if (IS_ERR(new)) {
- retv = PTR_ERR(new);
+ case IPV6_RTHDRDSTOPTS:
+ case IPV6_DSTOPTS:
+ max_len = net->ipv6.sysctl.max_dst_opts_len;
+ max_cnt = net->ipv6.sysctl.max_dst_opts_cnt;
break;
- }
- if (unlikely(ipv6_optlen(new) > optlen)) {
- kfree(new);
- goto e_inval;
- }
}
opt = rcu_dereference_protected(np->opt,
lockdep_sock_is_held(sk));
- opt = ipeh_renew_options(sk, opt, optname, new);
- kfree(new);
+ opt = ipeh_txopt_from_opt(sk, &ipv6_tlv_param_table, opt,
+ optname, optval, optlen, max_len,
+ max_cnt);
+
if (IS_ERR(opt)) {
retv = PTR_ERR(opt);
break;
--
2.21.0
^ permalink raw reply related
* [net-next 5/7] ip6tlvs: Add TX parameters
From: Jeff Kirsher @ 2019-08-22 22:59 UTC (permalink / raw)
To: davem; +Cc: Tom Herbert, netdev, nhorman, sassmann, Andrew Bowers,
Jeff Kirsher
In-Reply-To: <20190822225940.14235-1-jeffrey.t.kirsher@intel.com>
From: Tom Herbert <tom@herbertland.com>
Define a number of transmit parameters for TLV Parameter table
definitions. These will be used for validating TLVs that are set
on a socket.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/net/ipeh.h | 18 +++++++++++++
include/uapi/linux/ipeh.h | 8 ++++++
net/ipv6/exthdrs_common.c | 53 +++++++++++++++++++++++++++++++++++++-
net/ipv6/exthdrs_options.c | 45 ++++++++++++++++++++++++++++++++
4 files changed, 123 insertions(+), 1 deletion(-)
diff --git a/include/net/ipeh.h b/include/net/ipeh.h
index aaa2910be3ab..de6d9d05f43e 100644
--- a/include/net/ipeh.h
+++ b/include/net/ipeh.h
@@ -20,6 +20,17 @@ struct tlv_rx_params {
};
struct tlv_tx_params {
+ unsigned char admin_perm : 2;
+ unsigned char user_perm : 2;
+ unsigned char class : 3;
+ unsigned char rsvd : 1;
+ unsigned char align_mult : 4;
+ unsigned char align_off : 4;
+ unsigned char data_len_mult : 4;
+ unsigned char data_len_off : 4;
+ unsigned char min_data_len;
+ unsigned char max_data_len;
+ unsigned short preferred_order;
};
struct tlv_params {
@@ -54,6 +65,13 @@ struct tlv_param_table {
extern struct tlv_param_table ipv6_tlv_param_table;
+/* Preferred TLV ordering for HBH and Dest options (placed by increasing order)
+ */
+#define IPEH_TLV_PREF_ORDER_HAO 10
+#define IPEH_TLV_PREF_ORDER_ROUTERALERT 20
+#define IPEH_TLV_PREF_ORDER_JUMBO 30
+#define IPEH_TLV_PREF_ORDER_CALIPSO 40
+
int __ipeh_tlv_set(struct tlv_param_table *tlv_param_table,
unsigned char type, const struct tlv_params *params,
const struct tlv_ops *ops);
diff --git a/include/uapi/linux/ipeh.h b/include/uapi/linux/ipeh.h
index c4302b7edd3e..dbf0728ddce4 100644
--- a/include/uapi/linux/ipeh.h
+++ b/include/uapi/linux/ipeh.h
@@ -13,4 +13,12 @@
IPEH_TLV_CLASS_FLAG_RTRDSTOPT | \
IPEH_TLV_CLASS_FLAG_DSTOPT)
+/* TLV permissions values */
+enum {
+ IPEH_TLV_PERM_NONE,
+ IPEH_TLV_PERM_WITH_CHECK,
+ IPEH_TLV_PERM_NO_CHECK,
+ IPEH_TLV_PERM_MAX = IPEH_TLV_PERM_NO_CHECK
+};
+
#endif /* _UAPI_LINUX_IPEH_H */
diff --git a/net/ipv6/exthdrs_common.c b/net/ipv6/exthdrs_common.c
index cc8db9e43ec2..791f6e4036c7 100644
--- a/net/ipv6/exthdrs_common.c
+++ b/net/ipv6/exthdrs_common.c
@@ -3,6 +3,7 @@
/* Extension header and TLV library code that is not specific to IPv6. */
#include <linux/export.h>
#include <net/ipv6.h>
+#include <uapi/linux/ipeh.h>
struct ipv6_txoptions *
ipeh_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
@@ -265,6 +266,13 @@ EXPORT_SYMBOL(ipeh_parse_tlv);
/* Default (unset) values for TLV parameters */
static const struct tlv_proc tlv_default_proc = {
+ .params.t = {
+ .admin_perm = IPEH_TLV_PERM_NO_CHECK,
+ .user_perm = IPEH_TLV_PERM_NONE,
+ .align_mult = (4 - 1), /* Default alignment: 4n + 2 */
+ .align_off = 2,
+ .max_data_len = 255,
+ },
};
static DEFINE_MUTEX(tlv_mutex);
@@ -283,6 +291,29 @@ static void tlv_param_table_release(struct rcu_head *rcu)
kvfree(tpt);
}
+/* mutex held */
+static int check_order(struct tlv_param_table_data *tpt, unsigned char type,
+ unsigned short order)
+{
+ int i;
+
+ if (!order)
+ return -EINVAL;
+
+ for (i = 2; i < 256; i++) {
+ struct tlv_type *ttype = &tpt->types[tpt->entries[i]];
+
+ if (!tpt->entries[i])
+ continue;
+
+ if (order == ttype->proc.params.t.preferred_order &&
+ i != type)
+ return -EALREADY;
+ }
+
+ return 0;
+}
+
/* mutex held */
static int __tlv_set_one(struct tlv_param_table *tlv_param_table,
unsigned char type, const struct tlv_params *params,
@@ -290,10 +321,16 @@ static int __tlv_set_one(struct tlv_param_table *tlv_param_table,
{
struct tlv_param_table_data *tpt, *told;
struct tlv_type *ttype;
+ int retv;
told = rcu_dereference_protected(tlv_param_table->data,
lockdep_is_held(&tlv_mutex));
+ /* Check preferred order */
+ retv = check_order(told, type, params->t.preferred_order);
+ if (retv)
+ return retv;
+
/* Create new TLV table. If there is no exsiting entry then we are
* adding a new one to the table, else we're modifying an entry.
*/
@@ -422,7 +459,7 @@ int ipeh_exthdrs_init(struct tlv_param_table *tlv_param_table,
int num_init_params)
{
struct tlv_param_table_data *tpt;
- int pos = 0, i;
+ int pos = 0, i, j;
size_t tsize;
tsize = tlv_param_table_size(num_init_params + 1);
@@ -448,6 +485,20 @@ int ipeh_exthdrs_init(struct tlv_param_table *tlv_param_table,
goto err_inval;
}
+ if (WARN_ON(!tpi->proc.params.t.preferred_order)) {
+ /* Preferred order must be non-zero */
+ goto err_inval;
+ }
+
+ for (j = 0; j < i; j++) {
+ const struct tlv_proc_init *tpix = &tlv_init_params[j];
+
+ if (WARN_ON(tpi->proc.params.t.preferred_order ==
+ tpix->proc.params.t.preferred_order)) {
+ /* Preferred order must be unique */
+ goto err_inval;
+ }
+ }
tpt->types[pos].proc = tpi->proc;
tpt->entries[tpi->type] = pos;
}
diff --git a/net/ipv6/exthdrs_options.c b/net/ipv6/exthdrs_options.c
index d4b373e1df96..3b50b584dd2d 100644
--- a/net/ipv6/exthdrs_options.c
+++ b/net/ipv6/exthdrs_options.c
@@ -183,6 +183,17 @@ static const struct tlv_proc_init tlv_ipv6_init_params[] __initconst = {
.proc.ops.func = ipv6_dest_hao,
.proc.params.r.class = IPEH_TLV_CLASS_FLAG_DSTOPT,
+
+ .proc.params.t = {
+ .preferred_order = IPEH_TLV_PREF_ORDER_HAO,
+ .admin_perm = IPEH_TLV_PERM_NO_CHECK,
+ .user_perm = IPEH_TLV_PERM_NONE,
+ .class = IPEH_TLV_CLASS_FLAG_DSTOPT,
+ .align_mult = (8 - 1), /* Align to 8n + 6 */
+ .align_off = 6,
+ .min_data_len = 16,
+ .max_data_len = 16,
+ },
},
#endif
{
@@ -190,18 +201,52 @@ static const struct tlv_proc_init tlv_ipv6_init_params[] __initconst = {
.proc.ops.func = ipv6_hop_ra,
.proc.params.r.class = IPEH_TLV_CLASS_FLAG_HOPOPT,
+
+ .proc.params.t = {
+ .preferred_order = IPEH_TLV_PREF_ORDER_ROUTERALERT,
+ .admin_perm = IPEH_TLV_PERM_NO_CHECK,
+ .user_perm = IPEH_TLV_PERM_NONE,
+ .class = IPEH_TLV_CLASS_FLAG_HOPOPT,
+ .align_mult = (2 - 1), /* Align to 2n */
+ .min_data_len = 2,
+ .max_data_len = 2,
+ },
},
{
.type = IPV6_TLV_JUMBO,
.proc.ops.func = ipv6_hop_jumbo,
.proc.params.r.class = IPEH_TLV_CLASS_FLAG_HOPOPT,
+
+ .proc.params.t = {
+ .preferred_order = IPEH_TLV_PREF_ORDER_JUMBO,
+ .admin_perm = IPEH_TLV_PERM_NO_CHECK,
+ .user_perm = IPEH_TLV_PERM_NONE,
+ .class = IPEH_TLV_CLASS_FLAG_HOPOPT,
+ .align_mult = (4 - 1), /* Align to 4n + 2 */
+ .align_off = 2,
+ .min_data_len = 4,
+ .max_data_len = 4,
+ },
},
{
.type = IPV6_TLV_CALIPSO,
.proc.ops.func = ipv6_hop_calipso,
.proc.params.r.class = IPEH_TLV_CLASS_FLAG_HOPOPT,
+
+ .proc.params.t = {
+ .preferred_order = IPEH_TLV_PREF_ORDER_CALIPSO,
+ .admin_perm = IPEH_TLV_PERM_NO_CHECK,
+ .user_perm = IPEH_TLV_PERM_NONE,
+ .class = IPEH_TLV_CLASS_FLAG_HOPOPT,
+ .align_mult = (4 - 1), /* Align to 4n + 2 */
+ .align_off = 2,
+ .min_data_len = 8,
+ .max_data_len = 252,
+ .data_len_mult = (4 - 1),
+ /* Length is multiple of 4 */
+ },
},
};
--
2.21.0
^ permalink raw reply related
* [net-next 3/7] ipeh: Generic TLV parser
From: Jeff Kirsher @ 2019-08-22 22:59 UTC (permalink / raw)
To: davem; +Cc: Tom Herbert, netdev, nhorman, sassmann, Andrew Bowers,
Jeff Kirsher
In-Reply-To: <20190822225940.14235-1-jeffrey.t.kirsher@intel.com>
From: Tom Herbert <tom@herbertland.com>
Create a generic TLV parser. This will be used with various
extension headers that carry options including Destination,
Hop-by-Hop, Segment Routing TLVs, and other cases of simple
stateless parsing.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/net/ipeh.h | 25 ++++++
net/ipv6/exthdrs.c | 159 +++++++++-----------------------------
net/ipv6/exthdrs_common.c | 114 +++++++++++++++++++++++++++
3 files changed, 177 insertions(+), 121 deletions(-)
diff --git a/include/net/ipeh.h b/include/net/ipeh.h
index 3b248311613b..c1aa7b6b37a7 100644
--- a/include/net/ipeh.h
+++ b/include/net/ipeh.h
@@ -31,4 +31,29 @@ struct ipv6_txoptions *ipeh_renew_options(struct sock *sk,
struct ipv6_txoptions *ipeh_fixup_options(struct ipv6_txoptions *opt_space,
struct ipv6_txoptions *opt);
+/* Generic extension header TLV parser */
+
+enum ipeh_parse_errors {
+ IPEH_PARSE_ERR_PAD1, /* Excessive PAD1 */
+ IPEH_PARSE_ERR_PADN, /* Excessive PADN */
+ IPEH_PARSE_ERR_PADNZ, /* Non-zero padding data */
+ IPEH_PARSE_ERR_EH_TOOBIG, /* Length of EH exceeds limit */
+ IPEH_PARSE_ERR_OPT_TOOBIG, /* Option size exceeds limit */
+ IPEH_PARSE_ERR_OPT_TOOMANY, /* Option count exceeds limit */
+ IPEH_PARSE_ERR_OPT_UNK_DISALW, /* Unknown option disallowed */
+ IPEH_PARSE_ERR_OPT_UNK, /* Unknown option */
+};
+
+/* The generic TLV parser assumes that the type value of PAD1 is 0, and PADN
+ * is 1. This is true for Destination, Hop-by-Hop and current definition
+ * of Segment Routing TLVs.
+ */
+#define IPEH_TLV_PAD1 0
+#define IPEH_TLV_PADN 1
+
+bool ipeh_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb,
+ int max_count, int off, int len,
+ bool (*parse_error)(struct sk_buff *skb,
+ int off, enum ipeh_parse_errors error));
+
#endif /* _NET_IPEH_H */
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index e12d3a5a70b5..939d27c1d059 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -54,135 +54,50 @@
Generic functions
*********************/
-/* An unknown option is detected, decide what to do */
-
-static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff,
- bool disallow_unknowns)
+/* Handle parse errors from ipeh generic TLV parser */
+static bool ipv6_parse_error(struct sk_buff *skb, int off,
+ enum ipeh_parse_errors error)
{
- if (disallow_unknowns) {
- /* If unknown TLVs are disallowed by configuration
- * then always silently drop packet. Note this also
- * means no ICMP parameter problem is sent which
- * could be a good property to mitigate a reflection DOS
- * attack.
- */
-
- goto drop;
- }
-
- switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) {
- case 0: /* ignore */
- return true;
-
- case 1: /* drop packet */
- break;
-
- case 3: /* Send ICMP if not a multicast address and drop packet */
- /* Actually, it is redundant check. icmp_send
- will recheck in any case.
- */
- if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
+ switch (error) {
+ case IPEH_PARSE_ERR_OPT_UNK_DISALW:
+ /* Disallow unknown skip */
+ if (((skb_network_header(skb)[off] & 0xC0) >> 6) == 0) {
+ /* Silent drop */
break;
+ }
/* fall through */
- case 2: /* send ICMP PARM PROB regardless and drop packet */
- icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
- return false;
- }
-
-drop:
- kfree_skb(skb);
- return false;
-}
+ case IPEH_PARSE_ERR_OPT_UNK:
+ switch ((skb_network_header(skb)[off] & 0xC0) >> 6) {
+ case 0: /* ignore */
+ return true;
-/* Parse tlv encoded option header (hop-by-hop or destination) */
-
-static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
- struct sk_buff *skb,
- int max_count)
-{
- int len = (skb_transport_header(skb)[1] + 1) << 3;
- const unsigned char *nh = skb_network_header(skb);
- int off = skb_network_header_len(skb);
- const struct tlvtype_proc *curr;
- bool disallow_unknowns = false;
- int tlv_count = 0;
- int padlen = 0;
-
- if (unlikely(max_count < 0)) {
- disallow_unknowns = true;
- max_count = -max_count;
- }
-
- if (skb_transport_offset(skb) + len > skb_headlen(skb))
- goto bad;
-
- off += 2;
- len -= 2;
-
- while (len > 0) {
- int optlen = nh[off + 1] + 2;
- int i;
-
- switch (nh[off]) {
- case IPV6_TLV_PAD1:
- optlen = 1;
- padlen++;
- if (padlen > 7)
- goto bad;
+ case 1: /* drop packet */
break;
- case IPV6_TLV_PADN:
- /* RFC 2460 states that the purpose of PadN is
- * to align the containing header to multiples
- * of 8. 7 is therefore the highest valid value.
- * See also RFC 4942, Section 2.1.9.5.
- */
- padlen += optlen;
- if (padlen > 7)
- goto bad;
- /* RFC 4942 recommends receiving hosts to
- * actively check PadN payload to contain
- * only zeroes.
+ case 3: /* Send ICMP if not a multicast address and drop packet
+ *
+ * Actually, it is redundant check. icmp_send
+ * will recheck in any case.
*/
- for (i = 2; i < optlen; i++) {
- if (nh[off + i] != 0)
- goto bad;
- }
- break;
+ if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr))
+ break;
- default: /* Other TLV code so scan list */
- if (optlen > len)
- goto bad;
-
- tlv_count++;
- if (tlv_count > max_count)
- goto bad;
-
- for (curr = procs; curr->type >= 0; curr++) {
- if (curr->type == nh[off]) {
- /* type specific length/alignment
- checks will be performed in the
- func(). */
- if (curr->func(skb, off) == false)
- return false;
- break;
- }
- }
- if (curr->type < 0 &&
- !ip6_tlvopt_unknown(skb, off, disallow_unknowns))
- return false;
-
- padlen = 0;
+ /* fall through */
+ case 2: /* send ICMP PARM PROB regardless and drop packet */
+ icmpv6_send(skb, ICMPV6_PARAMPROB,
+ ICMPV6_UNK_OPTION, off);
break;
}
- off += optlen;
- len -= optlen;
+ break;
+ default:
+ break;
}
- if (len == 0)
- return true;
-bad:
- kfree_skb(skb);
+ /* Will be dropping packet */
+
+ __IP6_INC_STATS(dev_net(skb->dev), __in6_dev_get(skb->dev),
+ IPSTATS_MIB_INHDRERRORS);
+
return false;
}
@@ -216,8 +131,9 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
dstbuf = opt->dst1;
#endif
- if (ip6_parse_tlv(tlvprocdestopt_lst, skb,
- init_net.ipv6.sysctl.max_dst_opts_cnt)) {
+ if (ipeh_parse_tlv(tlvprocdestopt_lst, skb,
+ init_net.ipv6.sysctl.max_dst_opts_cnt,
+ 2, extlen - 2, ipv6_parse_error)) {
skb->transport_header += extlen;
opt = IP6CB(skb);
#if IS_ENABLED(CONFIG_IPV6_MIP6)
@@ -639,8 +555,9 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
goto fail_and_free;
opt->flags |= IP6SKB_HOPBYHOP;
- if (ip6_parse_tlv(tlvprochopopt_lst, skb,
- init_net.ipv6.sysctl.max_hbh_opts_cnt)) {
+ if (ipeh_parse_tlv(tlvprochopopt_lst, skb,
+ init_net.ipv6.sysctl.max_hbh_opts_cnt,
+ 2, extlen - 2, ipv6_parse_error)) {
skb->transport_header += extlen;
opt = IP6CB(skb);
opt->nhoff = sizeof(struct ipv6hdr);
diff --git a/net/ipv6/exthdrs_common.c b/net/ipv6/exthdrs_common.c
index 2c68184f2e1a..99a0911d8315 100644
--- a/net/ipv6/exthdrs_common.c
+++ b/net/ipv6/exthdrs_common.c
@@ -142,3 +142,117 @@ struct ipv6_txoptions *ipeh_fixup_options(struct ipv6_txoptions *opt_space,
return opt;
}
EXPORT_SYMBOL_GPL(ipeh_fixup_options);
+
+/* Generic extension header TLV parser
+ *
+ * Arguments:
+ * - skb_transport_header points to the extension header containing options
+ * - off is offset from skb_transport_header where first TLV is
+ * - len is length of TLV block
+ */
+bool ipeh_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb,
+ int max_count, int off, int len,
+ bool (*parse_error)(struct sk_buff *skb,
+ int off, enum ipeh_parse_errors error))
+{
+ const unsigned char *nh = skb_network_header(skb);
+ const struct tlvtype_proc *curr;
+ bool disallow_unknowns = false;
+ int tlv_count = 0;
+ int padlen = 0;
+
+ if (unlikely(max_count < 0)) {
+ disallow_unknowns = true;
+ max_count = -max_count;
+ }
+
+ if (skb_transport_offset(skb) + off + len > skb_headlen(skb)) {
+ if (!parse_error(skb, skb_transport_offset(skb),
+ IPEH_PARSE_ERR_EH_TOOBIG))
+ goto bad;
+
+ len = skb_headlen(skb) - skb_transport_offset(skb) - off;
+ }
+
+ /* ops function based offset on network header */
+ off += skb_network_header_len(skb);
+
+ while (len > 0) {
+ int optlen = nh[off + 1] + 2;
+ int i;
+
+ switch (nh[off]) {
+ case IPEH_TLV_PAD1:
+ optlen = 1;
+ padlen++;
+ if (padlen > 7 &&
+ !parse_error(skb, off, IPEH_PARSE_ERR_PAD1))
+ goto bad;
+
+ break;
+
+ case IPEH_TLV_PADN:
+ /* RFC 2460 states that the purpose of PadN is
+ * to align the containing header to multiples
+ * of 8. 7 is therefore the highest valid value.
+ * See also RFC 4942, Section 2.1.9.5.
+ */
+ padlen += optlen;
+ if (padlen > 7 &&
+ !parse_error(skb, off, IPEH_PARSE_ERR_PADN))
+ goto bad;
+
+ /* RFC 4942 recommends receiving hosts to
+ * actively check PadN payload to contain
+ * only zeroes.
+ */
+ for (i = 2; i < optlen; i++) {
+ if (nh[off + i] != 0 &&
+ !parse_error(skb, off + i,
+ IPEH_PARSE_ERR_PADNZ))
+ goto bad;
+ }
+ break;
+
+ default: /* Other TLV code so scan list */
+ if (optlen > len &&
+ !parse_error(skb, off, IPEH_PARSE_ERR_OPT_TOOBIG))
+ goto bad;
+
+ tlv_count++;
+ if (tlv_count > max_count &&
+ parse_error(skb, off, IPEH_PARSE_ERR_OPT_TOOMANY))
+ goto bad;
+
+ for (curr = procs; curr->type >= 0; curr++) {
+ if (curr->type == nh[off]) {
+ /* type specific length/alignment
+ * checks will be performed in the
+ * func().
+ */
+ if (curr->func(skb, off) == false)
+ return false;
+ break;
+ }
+ }
+ if (curr->type < 0 &&
+ !parse_error(skb, off,
+ disallow_unknowns ?
+ IPEH_PARSE_ERR_OPT_UNK_DISALW :
+ IPEH_PARSE_ERR_OPT_UNK))
+ goto bad;
+
+ padlen = 0;
+ break;
+ }
+ off += optlen;
+ len -= optlen;
+ }
+
+ if (len == 0)
+ return true;
+bad:
+ kfree_skb(skb);
+ return false;
+}
+EXPORT_SYMBOL(ipeh_parse_tlv);
--
2.21.0
^ permalink raw reply related
* [net-next 2/7] ipeh: Move generic EH functions to exthdrs_common.c
From: Jeff Kirsher @ 2019-08-22 22:59 UTC (permalink / raw)
To: davem
Cc: Tom Herbert, netdev, nhorman, sassmann, kbuild test robot,
Andrew Bowers, Jeff Kirsher
In-Reply-To: <20190822225940.14235-1-jeffrey.t.kirsher@intel.com>
From: Tom Herbert <tom@herbertland.com>
Move generic functions in exthdrs.c to new exthdrs_common.c so that
exthdrs.c only contains functions that are specific to IPv6 processing,
and exthdrs_common.c contains functions that are generic. These
functions include those that will be used with IPv4 extension headers.
Generic extension header related functions are prefixed by ipeh_.
Fix kbuild issue.
Reported-by: kbuild test robot <lkp@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/net/ipeh.h | 12 ++++
include/net/ipv6.h | 9 ---
net/dccp/ipv6.c | 2 +-
net/ipv6/Kconfig | 4 ++
net/ipv6/Makefile | 1 +
net/ipv6/calipso.c | 6 +-
net/ipv6/exthdrs.c | 138 ------------------------------------
net/ipv6/exthdrs_common.c | 144 ++++++++++++++++++++++++++++++++++++++
net/ipv6/ipv6_sockglue.c | 2 +-
net/ipv6/raw.c | 2 +-
net/ipv6/tcp_ipv6.c | 2 +-
net/ipv6/udp.c | 2 +-
net/l2tp/l2tp_ip6.c | 2 +-
net/sctp/ipv6.c | 2 +-
14 files changed, 171 insertions(+), 157 deletions(-)
create mode 100644 net/ipv6/exthdrs_common.c
diff --git a/include/net/ipeh.h b/include/net/ipeh.h
index ec2d18609e0f..3b248311613b 100644
--- a/include/net/ipeh.h
+++ b/include/net/ipeh.h
@@ -19,4 +19,16 @@ struct tlvtype_proc {
extern const struct tlvtype_proc tlvprocdestopt_lst[];
extern const struct tlvtype_proc tlvprochopopt_lst[];
+struct ipv6_txoptions;
+struct ipv6_opt_hdr;
+
+struct ipv6_txoptions *ipeh_dup_options(struct sock *sk,
+ struct ipv6_txoptions *opt);
+struct ipv6_txoptions *ipeh_renew_options(struct sock *sk,
+ struct ipv6_txoptions *opt,
+ int newtype,
+ struct ipv6_opt_hdr *newopt);
+struct ipv6_txoptions *ipeh_fixup_options(struct ipv6_txoptions *opt_space,
+ struct ipv6_txoptions *opt);
+
#endif /* _NET_IPEH_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index ec10fcab3f3d..1c6878b73db2 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -429,15 +429,6 @@ int ip6_ra_control(struct sock *sk, int sel);
int ipv6_parse_hopopts(struct sk_buff *skb);
-struct ipv6_txoptions *ipv6_dup_options(struct sock *sk,
- struct ipv6_txoptions *opt);
-struct ipv6_txoptions *ipv6_renew_options(struct sock *sk,
- struct ipv6_txoptions *opt,
- int newtype,
- struct ipv6_opt_hdr *newopt);
-struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
- struct ipv6_txoptions *opt);
-
bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb,
const struct inet6_skb_parm *opt);
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 1b7381ff787b..0b83a04783e4 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -514,7 +514,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
if (!opt)
opt = rcu_dereference(np->opt);
if (opt) {
- opt = ipv6_dup_options(newsk, opt);
+ opt = ipeh_dup_options(newsk, opt);
RCU_INIT_POINTER(newnp->opt, opt);
}
inet_csk(newsk)->icsk_ext_hdr_len = 0;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ae1344e4cec5..700fcea17357 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -3,9 +3,13 @@
# IPv6 configuration
#
+config EXTHDRS
+ bool
+
# IPv6 as module will cause a CRASH if you try to unload it
menuconfig IPV6
tristate "The IPv6 protocol"
+ select EXTHDRS
default y
---help---
Support for IP version 6 (IPv6).
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index df3919b44d93..0bcab817244e 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
obj-$(CONFIG_IPV6_FOU) += fou6.o
+obj-$(CONFIG_EXTHDRS) += exthdrs_common.o
obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
index 221c81f85cbf..9c8484852d4c 100644
--- a/net/ipv6/calipso.c
+++ b/net/ipv6/calipso.c
@@ -785,7 +785,7 @@ static int calipso_opt_update(struct sock *sk, struct ipv6_opt_hdr *hop)
{
struct ipv6_txoptions *old = txopt_get(inet6_sk(sk)), *txopts;
- txopts = ipv6_renew_options(sk, old, IPV6_HOPOPTS, hop);
+ txopts = ipeh_renew_options(sk, old, IPV6_HOPOPTS, hop);
txopt_put(old);
if (IS_ERR(txopts))
return PTR_ERR(txopts);
@@ -1207,7 +1207,7 @@ static int calipso_req_setattr(struct request_sock *req,
if (IS_ERR(new))
return PTR_ERR(new);
- txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
+ txopts = ipeh_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
kfree(new);
@@ -1244,7 +1244,7 @@ static void calipso_req_delattr(struct request_sock *req)
if (calipso_opt_del(req_inet->ipv6_opt->hopopt, &new))
return; /* Nothing to do */
- txopts = ipv6_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
+ txopts = ipeh_renew_options(sk, req_inet->ipv6_opt, IPV6_HOPOPTS, new);
if (!IS_ERR(txopts)) {
txopts = xchg(&req_inet->ipv6_opt, txopts);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 664491e8115f..e12d3a5a70b5 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -784,144 +784,6 @@ void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *pr
}
EXPORT_SYMBOL(ipv6_push_frag_opts);
-struct ipv6_txoptions *
-ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
-{
- struct ipv6_txoptions *opt2;
-
- opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
- if (opt2) {
- long dif = (char *)opt2 - (char *)opt;
- memcpy(opt2, opt, opt->tot_len);
- if (opt2->hopopt)
- *((char **)&opt2->hopopt) += dif;
- if (opt2->dst0opt)
- *((char **)&opt2->dst0opt) += dif;
- if (opt2->dst1opt)
- *((char **)&opt2->dst1opt) += dif;
- if (opt2->srcrt)
- *((char **)&opt2->srcrt) += dif;
- refcount_set(&opt2->refcnt, 1);
- }
- return opt2;
-}
-EXPORT_SYMBOL_GPL(ipv6_dup_options);
-
-static void ipv6_renew_option(int renewtype,
- struct ipv6_opt_hdr **dest,
- struct ipv6_opt_hdr *old,
- struct ipv6_opt_hdr *new,
- int newtype, char **p)
-{
- struct ipv6_opt_hdr *src;
-
- src = (renewtype == newtype ? new : old);
- if (!src)
- return;
-
- memcpy(*p, src, ipv6_optlen(src));
- *dest = (struct ipv6_opt_hdr *)*p;
- *p += CMSG_ALIGN(ipv6_optlen(*dest));
-}
-
-/**
- * ipv6_renew_options - replace a specific ext hdr with a new one.
- *
- * @sk: sock from which to allocate memory
- * @opt: original options
- * @newtype: option type to replace in @opt
- * @newopt: new option of type @newtype to replace (user-mem)
- * @newoptlen: length of @newopt
- *
- * Returns a new set of options which is a copy of @opt with the
- * option type @newtype replaced with @newopt.
- *
- * @opt may be NULL, in which case a new set of options is returned
- * containing just @newopt.
- *
- * @newopt may be NULL, in which case the specified option type is
- * not copied into the new set of options.
- *
- * The new set of options is allocated from the socket option memory
- * buffer of @sk.
- */
-struct ipv6_txoptions *
-ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
- int newtype, struct ipv6_opt_hdr *newopt)
-{
- int tot_len = 0;
- char *p;
- struct ipv6_txoptions *opt2;
-
- if (opt) {
- if (newtype != IPV6_HOPOPTS && opt->hopopt)
- tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
- if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
- tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
- if (newtype != IPV6_RTHDR && opt->srcrt)
- tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
- if (newtype != IPV6_DSTOPTS && opt->dst1opt)
- tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
- }
-
- if (newopt)
- tot_len += CMSG_ALIGN(ipv6_optlen(newopt));
-
- if (!tot_len)
- return NULL;
-
- tot_len += sizeof(*opt2);
- opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
- if (!opt2)
- return ERR_PTR(-ENOBUFS);
-
- memset(opt2, 0, tot_len);
- refcount_set(&opt2->refcnt, 1);
- opt2->tot_len = tot_len;
- p = (char *)(opt2 + 1);
-
- ipv6_renew_option(IPV6_HOPOPTS, &opt2->hopopt,
- (opt ? opt->hopopt : NULL),
- newopt, newtype, &p);
- ipv6_renew_option(IPV6_RTHDRDSTOPTS, &opt2->dst0opt,
- (opt ? opt->dst0opt : NULL),
- newopt, newtype, &p);
- ipv6_renew_option(IPV6_RTHDR,
- (struct ipv6_opt_hdr **)&opt2->srcrt,
- (opt ? (struct ipv6_opt_hdr *)opt->srcrt : NULL),
- newopt, newtype, &p);
- ipv6_renew_option(IPV6_DSTOPTS, &opt2->dst1opt,
- (opt ? opt->dst1opt : NULL),
- newopt, newtype, &p);
-
- opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
- (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
- (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
- opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
-
- return opt2;
-}
-
-struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
- struct ipv6_txoptions *opt)
-{
- /*
- * ignore the dest before srcrt unless srcrt is being included.
- * --yoshfuji
- */
- if (opt && opt->dst0opt && !opt->srcrt) {
- if (opt_space != opt) {
- memcpy(opt_space, opt, sizeof(*opt_space));
- opt = opt_space;
- }
- opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
- opt->dst0opt = NULL;
- }
-
- return opt;
-}
-EXPORT_SYMBOL_GPL(ipv6_fixup_options);
-
/**
* fl6_update_dst - update flowi destination address with info given
* by srcrt option, if any.
diff --git a/net/ipv6/exthdrs_common.c b/net/ipv6/exthdrs_common.c
new file mode 100644
index 000000000000..2c68184f2e1a
--- /dev/null
+++ b/net/ipv6/exthdrs_common.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Extension header and TLV library code that is not specific to IPv6. */
+#include <linux/export.h>
+#include <net/ipv6.h>
+
+struct ipv6_txoptions *
+ipeh_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
+{
+ struct ipv6_txoptions *opt2;
+
+ opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC);
+ if (opt2) {
+ long dif = (char *)opt2 - (char *)opt;
+
+ memcpy(opt2, opt, opt->tot_len);
+ if (opt2->hopopt)
+ *((char **)&opt2->hopopt) += dif;
+ if (opt2->dst0opt)
+ *((char **)&opt2->dst0opt) += dif;
+ if (opt2->dst1opt)
+ *((char **)&opt2->dst1opt) += dif;
+ if (opt2->srcrt)
+ *((char **)&opt2->srcrt) += dif;
+ refcount_set(&opt2->refcnt, 1);
+ }
+ return opt2;
+}
+EXPORT_SYMBOL_GPL(ipeh_dup_options);
+
+static void ipeh_renew_option(int renewtype,
+ struct ipv6_opt_hdr **dest,
+ struct ipv6_opt_hdr *old,
+ struct ipv6_opt_hdr *new,
+ int newtype, char **p)
+{
+ struct ipv6_opt_hdr *src;
+
+ src = (renewtype == newtype ? new : old);
+ if (!src)
+ return;
+
+ memcpy(*p, src, ipv6_optlen(src));
+ *dest = (struct ipv6_opt_hdr *)*p;
+ *p += CMSG_ALIGN(ipv6_optlen(*dest));
+}
+
+/**
+ * ipeh_renew_options - replace a specific ext hdr with a new one.
+ *
+ * @sk: sock from which to allocate memory
+ * @opt: original options
+ * @newtype: option type to replace in @opt
+ * @newopt: new option of type @newtype to replace (user-mem)
+ * @newoptlen: length of @newopt
+ *
+ * Returns a new set of options which is a copy of @opt with the
+ * option type @newtype replaced with @newopt.
+ *
+ * @opt may be NULL, in which case a new set of options is returned
+ * containing just @newopt.
+ *
+ * @newopt may be NULL, in which case the specified option type is
+ * not copied into the new set of options.
+ *
+ * The new set of options is allocated from the socket option memory
+ * buffer of @sk.
+ */
+struct ipv6_txoptions *
+ipeh_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
+ int newtype, struct ipv6_opt_hdr *newopt)
+{
+ int tot_len = 0;
+ char *p;
+ struct ipv6_txoptions *opt2;
+
+ if (opt) {
+ if (newtype != IPV6_HOPOPTS && opt->hopopt)
+ tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt));
+ if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt)
+ tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt));
+ if (newtype != IPV6_RTHDR && opt->srcrt)
+ tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt));
+ if (newtype != IPV6_DSTOPTS && opt->dst1opt)
+ tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt));
+ }
+
+ if (newopt)
+ tot_len += CMSG_ALIGN(ipv6_optlen(newopt));
+
+ if (!tot_len)
+ return NULL;
+
+ tot_len += sizeof(*opt2);
+ opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC);
+ if (!opt2)
+ return ERR_PTR(-ENOBUFS);
+
+ memset(opt2, 0, tot_len);
+ refcount_set(&opt2->refcnt, 1);
+ opt2->tot_len = tot_len;
+ p = (char *)(opt2 + 1);
+
+ ipeh_renew_option(IPV6_HOPOPTS, &opt2->hopopt,
+ (opt ? opt->hopopt : NULL),
+ newopt, newtype, &p);
+ ipeh_renew_option(IPV6_RTHDRDSTOPTS, &opt2->dst0opt,
+ (opt ? opt->dst0opt : NULL),
+ newopt, newtype, &p);
+ ipeh_renew_option(IPV6_RTHDR,
+ (struct ipv6_opt_hdr **)&opt2->srcrt,
+ (opt ? (struct ipv6_opt_hdr *)opt->srcrt : NULL),
+ newopt, newtype, &p);
+ ipeh_renew_option(IPV6_DSTOPTS, &opt2->dst1opt,
+ (opt ? opt->dst1opt : NULL),
+ newopt, newtype, &p);
+
+ opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) +
+ (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) +
+ (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0);
+ opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0);
+
+ return opt2;
+}
+EXPORT_SYMBOL(ipeh_renew_options);
+
+struct ipv6_txoptions *ipeh_fixup_options(struct ipv6_txoptions *opt_space,
+ struct ipv6_txoptions *opt)
+{
+ /* ignore the dest before srcrt unless srcrt is being included.
+ * --yoshfuji
+ */
+ if (opt && opt->dst0opt && !opt->srcrt) {
+ if (opt_space != opt) {
+ memcpy(opt_space, opt, sizeof(*opt_space));
+ opt = opt_space;
+ }
+ opt->opt_nflen -= ipv6_optlen(opt->dst0opt);
+ opt->dst0opt = NULL;
+ }
+
+ return opt;
+}
+EXPORT_SYMBOL_GPL(ipeh_fixup_options);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 264c292e7dcc..8755ecc13d0e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -427,7 +427,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
opt = rcu_dereference_protected(np->opt,
lockdep_sock_is_held(sk));
- opt = ipv6_renew_options(sk, opt, optname, new);
+ opt = ipeh_renew_options(sk, opt, optname, new);
kfree(new);
if (IS_ERR(opt)) {
retv = PTR_ERR(opt);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 8a6131991e38..5834ca4ae0f4 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -888,7 +888,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
if (flowlabel)
opt = fl6_merge_options(&opt_space, flowlabel, opt);
- opt = ipv6_fixup_options(&opt_space, opt);
+ opt = ipeh_fixup_options(&opt_space, opt);
fl6.flowi6_proto = proto;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 87f44d3250ee..6bbf24f1eb09 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1243,7 +1243,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
if (!opt)
opt = rcu_dereference(np->opt);
if (opt) {
- opt = ipv6_dup_options(newsk, opt);
+ opt = ipeh_dup_options(newsk, opt);
RCU_INIT_POINTER(newnp->opt, opt);
}
inet_csk(newsk)->icsk_ext_hdr_len = 0;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 827fe7385078..02ab20ebfe44 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1384,7 +1384,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
if (flowlabel)
opt = fl6_merge_options(&opt_space, flowlabel, opt);
- opt = ipv6_fixup_options(&opt_space, opt);
+ opt = ipeh_fixup_options(&opt_space, opt);
ipc6.opt = opt;
fl6.flowi6_proto = sk->sk_protocol;
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 687e23a8b326..bc4925c2e4bc 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -590,7 +590,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
if (flowlabel)
opt = fl6_merge_options(&opt_space, flowlabel, opt);
- opt = ipv6_fixup_options(&opt_space, opt);
+ opt = ipeh_fixup_options(&opt_space, opt);
ipc6.opt = opt;
fl6.flowi6_proto = sk->sk_protocol;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e5f2fc726a98..b5b134934827 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -441,7 +441,7 @@ static void sctp_v6_copy_ip_options(struct sock *sk, struct sock *newsk)
rcu_read_lock();
opt = rcu_dereference(np->opt);
if (opt) {
- opt = ipv6_dup_options(newsk, opt);
+ opt = ipeh_dup_options(newsk, opt);
if (!opt)
pr_err("%s: Failed to copy ip options\n", __func__);
}
--
2.21.0
^ permalink raw reply related
* Re: r8169: regression on MIPS/Loongson
From: David Miller @ 2019-08-22 23:00 UTC (permalink / raw)
To: hkallweit1; +Cc: aaro.koskinen, netdev, linux-mips
In-Reply-To: <d76b0614-188e-885c-b346-b131cc1d9688@gmail.com>
From: Heiner Kallweit <hkallweit1@gmail.com>
Date: Fri, 23 Aug 2019 00:52:34 +0200
> Typically the Realtek chips are used on Intel platforms and I haven't
> seen any such report yet, so it seems to be platform-specific.
> Which board (DT config) is it, and can you provide a full dmesg?
Unfortunately on Intel you're not going to be testing the DMA syncing
very much except with full debugging enabled where it'll use bounce
buffers which give a reasonable simulation of what the non-cache-coherent
systems will be dealing with.
^ permalink raw reply
* Re: [net-next 0/7][pull request] ipv6: Extension header infrastructure
From: David Miller @ 2019-08-22 23:01 UTC (permalink / raw)
To: jeffrey.t.kirsher; +Cc: netdev, nhorman, sassmann
In-Reply-To: <20190822225940.14235-1-jeffrey.t.kirsher@intel.com>
Jeff, why are you submitting Tom's changes, can't he submit his
patches on his own?
^ permalink raw reply
* Re: [PATCH net-next 06/10] net: sched: conditionally obtain rtnl lock in cls hw offloads API
From: Jakub Kicinski @ 2019-08-22 23:03 UTC (permalink / raw)
To: Vlad Buslov; +Cc: netdev, jhs, xiyou.wangcong, jiri, davem, pablo, Jiri Pirko
In-Reply-To: <20190822124353.16902-7-vladbu@mellanox.com>
On Thu, 22 Aug 2019 15:43:49 +0300, Vlad Buslov wrote:
> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
> index 02a547aa77c0..bda42f1b5514 100644
> --- a/net/sched/cls_api.c
> +++ b/net/sched/cls_api.c
> @@ -3076,11 +3076,28 @@ __tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
> int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
> void *type_data, bool err_stop, bool rtnl_held)
> {
> + bool take_rtnl = false;
Should we perhaps speculatively:
bool take_rtnl = READ_ONCE(block->lockeddevcnt);
here? It shouldn't hurt, really, and otherwise every offload that
requires rtnl will have to re-lock cb_lock, every single time..
> int ok_count;
>
> +retry:
> + if (take_rtnl)
> + rtnl_lock();
> down_read(&block->cb_lock);
> + /* Need to obtain rtnl lock if block is bound to devs that require it.
> + * In block bind code cb_lock is obtained while holding rtnl, so we must
> + * obtain the locks in same order here.
> + */
> + if (!rtnl_held && !take_rtnl && block->lockeddevcnt) {
> + up_read(&block->cb_lock);
> + take_rtnl = true;
> + goto retry;
> + }
> +
> ok_count = __tc_setup_cb_call(block, type, type_data, err_stop);
> +
> up_read(&block->cb_lock);
> + if (take_rtnl)
> + rtnl_unlock();
> return ok_count;
> }
> EXPORT_SYMBOL(tc_setup_cb_call);
^ permalink raw reply
* Re: [net-next 0/7][pull request] ipv6: Extension header infrastructure
From: David Miller @ 2019-08-22 23:08 UTC (permalink / raw)
To: jeffrey.t.kirsher; +Cc: netdev, nhorman, sassmann
In-Reply-To: <20190822.160144.1301428429264860069.davem@davemloft.net>
From: David Miller <davem@davemloft.net>
Date: Thu, 22 Aug 2019 16:01:44 -0700 (PDT)
> Jeff, why are you submitting Tom's changes, can't he submit his
> patches on his own?
Just in case it isn't clear.
Tom has submitted these changes in the past, there were objections made
to them. Tom must keep submitting these changes himself and continue
the discussion if these changes are to be taken seriously.
Therefore I have tossed this submission from patchwork.
^ permalink raw reply
* Re: [PATCH v2] net: pch_gbe: Fix memory leaks
From: David Miller @ 2019-08-22 23:11 UTC (permalink / raw)
To: wenwen
Cc: rfontana, alexios.zavras, allison, gregkh, tglx, netdev,
linux-kernel
In-Reply-To: <1566361206-5135-1-git-send-email-wenwen@cs.uga.edu>
From: Wenwen Wang <wenwen@cs.uga.edu>
Date: Tue, 20 Aug 2019 23:20:05 -0500
> In pch_gbe_set_ringparam(), if netif_running() returns false, 'tx_old' and
> 'rx_old' are not deallocated, leading to memory leaks. To fix this issue,
> move the free statements to the outside of the if() statement.
>
> Signed-off-by: Wenwen Wang <wenwen@cs.uga.edu>
Something still is not right here.
> diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
> index 1a3008e..cb43919 100644
> --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
> +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c
> @@ -340,12 +340,10 @@ static int pch_gbe_set_ringparam(struct net_device *netdev,
> goto err_setup_tx;
> pch_gbe_free_rx_resources(adapter, rx_old);
> pch_gbe_free_tx_resources(adapter, tx_old);
> - kfree(tx_old);
> - kfree(rx_old);
> - adapter->rx_ring = rxdr;
> - adapter->tx_ring = txdr;
> err = pch_gbe_up(adapter);
> }
> + kfree(tx_old);
> + kfree(rx_old);
If the if() condition ending here is not taken, you cannot just free these
two pointers. You are then leaking the memory which would normally be
liberated by pch_gbe_free_rx_resources() and pch_gbe_free_tx_resources().
What's more, in this same situation, the rx_old->dma value is probably still
programmed into the hardware, and therefore the device still could potentially
DMA read/write to that memory.
I think the fix here is not simple, and you will need to do more extensive
research in order to fix this properly.
I'm not applying this, sorry.
^ permalink raw reply
* Re: [PATCH v2] qed: Add cleanup in qed_slowpath_start()
From: David Miller @ 2019-08-22 23:11 UTC (permalink / raw)
To: wenwen; +Cc: skalluru, aelior, GR-everest-linux-l2, netdev, linux-kernel
In-Reply-To: <1566362796-5399-1-git-send-email-wenwen@cs.uga.edu>
From: Wenwen Wang <wenwen@cs.uga.edu>
Date: Tue, 20 Aug 2019 23:46:36 -0500
> If qed_mcp_send_drv_version() fails, no cleanup is executed, leading to
> memory leaks. To fix this issue, introduce the label 'err4' to perform the
> cleanup work before returning the error.
>
> Signed-off-by: Wenwen Wang <wenwen@cs.uga.edu>
Applied.
^ permalink raw reply
* Re: pull-request: wireless-drivers 2019-08-21
From: David Miller @ 2019-08-22 23:12 UTC (permalink / raw)
To: kvalo; +Cc: linux-wireless, netdev, linux-kernel, johannes
In-Reply-To: <87zhk359wd.fsf@kamboji.qca.qualcomm.com>
From: Kalle Valo <kvalo@codeaurora.org>
Date: Wed, 21 Aug 2019 09:07:30 +0300
> here's a pull request to net for 5.3, more info below. I will be offline
> the next week, but Johannes should be able to help if there are any
> issues.
Pulled, thanks Kalle.
^ permalink raw reply
* Re: [PATCH net-next] net: dsa: remove bitmap operations
From: David Miller @ 2019-08-22 23:14 UTC (permalink / raw)
To: vivien.didelot; +Cc: netdev, f.fainelli, andrew, olteanv
In-Reply-To: <20190822161728.GB1471@t480s.localdomain>
From: Vivien Didelot <vivien.didelot@gmail.com>
Date: Thu, 22 Aug 2019 16:17:28 -0400
> David, I've included this patch into a new series with other related patches,
> you can ignore this one now.
Ok, thanks for letting me know.
^ permalink raw reply
* Re: [PATCH v2 net] Add genphy_c45_config_aneg() function to phy-c45.c
From: David Miller @ 2019-08-22 23:15 UTC (permalink / raw)
To: marco.hartmann
Cc: andrew, f.fainelli, hkallweit1, netdev, linux-kernel,
christian.herber
In-Reply-To: <1566385208-23523-1-git-send-email-marco.hartmann@nxp.com>
From: Marco Hartmann <marco.hartmann@nxp.com>
Date: Wed, 21 Aug 2019 11:00:46 +0000
> Commit 34786005eca3 ("net: phy: prevent PHYs w/o Clause 22 regs from calling
> genphy_config_aneg") introduced a check that aborts phy_config_aneg()
> if the phy is a C45 phy.
> This causes phy_state_machine() to call phy_error() so that the phy
> ends up in PHY_HALTED state.
>
> Instead of returning -EOPNOTSUPP, call genphy_c45_config_aneg()
> (analogous to the C22 case) so that the state machine can run
> correctly.
>
> genphy_c45_config_aneg() closely resembles mv3310_config_aneg()
> in drivers/net/phy/marvell10g.c, excluding vendor specific
> configurations for 1000BaseT.
>
> Fixes: 22b56e827093 ("net: phy: replace genphy_10g_driver with genphy_c45_driver")
>
> Signed-off-by: Marco Hartmann <marco.hartmann@nxp.com>
Andrew, Heiner, et al. where are we with this patch?
^ permalink raw reply
* Re: [PATCH v2 net-next] net: fec: add C45 MDIO read/write support
From: David Miller @ 2019-08-22 23:16 UTC (permalink / raw)
To: marco.hartmann; +Cc: fugang.duan, netdev, linux-kernel, christian.herber
In-Reply-To: <1566387814-7034-1-git-send-email-marco.hartmann@nxp.com>
From: Marco Hartmann <marco.hartmann@nxp.com>
Date: Wed, 21 Aug 2019 11:43:49 +0000
> IEEE 802.3ae clause 45 defines a modified MDIO protocol that uses a two
> staged access model in order to increase the address space.
>
> This patch adds support for C45 MDIO read and write accesses, which are
> used whenever the MII_ADDR_C45 flag in the regnum argument is set.
> In case it is not set, C22 accesses are used as before.
>
> Signed-off-by: Marco Hartmann <marco.hartmann@nxp.com>
> ---
> Changes in v2:
> - use bool variable is_c45
> - add missing goto statements
Applied, thank you.
^ permalink raw reply
* Re: [PATCH 1/2] rtnetlink: gate MAC address with an LSM hook
From: David Miller @ 2019-08-22 23:19 UTC (permalink / raw)
To: jeffv; +Cc: netdev, linux-security-module, selinux
In-Reply-To: <20190821134547.96929-1-jeffv@google.com>
From: Jeff Vander Stoep <jeffv@google.com>
Date: Wed, 21 Aug 2019 15:45:47 +0200
> MAC addresses are often considered sensitive because they are
> usually unique and can be used to identify/track a device or
> user [1].
>
> The MAC address is accessible via the RTM_NEWLINK message type of a
> netlink route socket[2]. Ideally we could grant/deny access to the
> MAC address on a case-by-case basis without blocking the entire
> RTM_NEWLINK message type which contains a lot of other useful
> information. This can be achieved using a new LSM hook on the netlink
> message receive path. Using this new hook, individual LSMs can select
> which processes are allowed access to the real MAC, otherwise a
> default value of zeros is returned. Offloading access control
> decisions like this to an LSM is convenient because it preserves the
> status quo for most Linux users while giving the various LSMs
> flexibility to make finer grained decisions on access to sensitive
> data based on policy.
>
> [1] https://adamdrake.com/mac-addresses-udids-and-privacy.html
> [2] Other access vectors like ioctl(SIOCGIFHWADDR) are already covered
> by existing LSM hooks.
>
> Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
I'm sure the MAC address will escape into userspace via other means,
dumping pieces of networking config in other contexts, etc. I mean,
if I can get a link dump, I can dump the neighbor table as well.
I kinda think this is all very silly whack-a-mole kind of stuff, to
be quite honest.
And like others have said, tomorrow you'll be like "oh crap, we should
block X too" and we'll get another hook, another config knob, another
rulset update, etc.
^ permalink raw reply
* Re: [PATCH net-next v2 0/3] net: dsa: mt7530: Convert to PHYLINK and add support for port 5
From: David Miller @ 2019-08-22 23:20 UTC (permalink / raw)
To: opensource
Cc: sean.wang, andrew, vivien.didelot, f.fainelli, matthias.bgg,
netdev, linux-arm-kernel, linux-mediatek, john, linux-mips,
frank-w
In-Reply-To: <20190821144547.15113-1-opensource@vdorst.com>
From: René van Dorst <opensource@vdorst.com>
Date: Wed, 21 Aug 2019 16:45:44 +0200
> 1. net: dsa: mt7530: Convert to PHYLINK API
> This patch converts mt7530 to PHYLINK API.
> 2. dt-bindings: net: dsa: mt7530: Add support for port 5
> 3. net: dsa: mt7530: Add support for port 5
> These 2 patches adding support for port 5 of the switch.
>
> v1->v2:
> * Mostly phylink improvements after review.
> rfc -> v1:
> * Mostly phylink improvements after review.
> * Drop phy isolation patches. Adds no value for now.
This definitely needs some review before I'll apply it.
Thanks.
^ permalink raw reply
* Re: [PATCH] mISDN: Delete unnecessary checks before the macro call “dev_kfree_skb”
From: David Miller @ 2019-08-22 23:23 UTC (permalink / raw)
To: Markus.Elfring
Cc: netdev, alexios.zavras, allison, armijn, arnd, huangfq.daxian,
gregkh, hkallweit1, kjlu, isdn, tglx, linux-kernel,
kernel-janitors
In-Reply-To: <689e51d5-9a43-45a4-5d33-75a34eba928a@web.de>
From: Markus Elfring <Markus.Elfring@web.de>
Date: Wed, 21 Aug 2019 20:45:09 +0200
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Wed, 21 Aug 2019 20:10:56 +0200
>
> The dev_kfree_skb() function performs also input parameter validation.
> Thus the test around the shown calls is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
Applied.
^ permalink raw reply
* Re: [PATCH] can: Delete unnecessary checks before the macro call “dev_kfree_skb”
From: David Miller @ 2019-08-22 23:23 UTC (permalink / raw)
To: Markus.Elfring
Cc: linux-can, netdev, allison, lkml, gregkh, gustavo, lukas, mkl,
sean, tglx, houweitaoo, wg, linux-kernel, kernel-janitors
In-Reply-To: <27674907-fd2a-7f0c-84fd-d8b5124739a9@web.de>
From: Markus Elfring <Markus.Elfring@web.de>
Date: Wed, 21 Aug 2019 21:30:11 +0200
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Wed, 21 Aug 2019 21:16:15 +0200
>
> The dev_kfree_skb() function performs also input parameter validation.
> Thus the test around the shown calls is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
Applied.
^ permalink raw reply
* Re: [PATCH] hamradio: Delete unnecessary checks before the macro call “dev_kfree_skb”
From: David Miller @ 2019-08-22 23:23 UTC (permalink / raw)
To: Markus.Elfring
Cc: linux-hams, netdev, allison, gregkh, kstewart, rfontana, tglx,
t.sailer, linux-kernel, kernel-janitors
In-Reply-To: <61fc7b82-dbc0-93e4-bf43-9856eb4c6688@web.de>
From: Markus Elfring <Markus.Elfring@web.de>
Date: Wed, 21 Aug 2019 22:00:16 +0200
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Wed, 21 Aug 2019 21:48:46 +0200
>
> The dev_kfree_skb() function performs also input parameter validation.
> Thus the test around the shown calls is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
Applied.
^ permalink raw reply
* Re: [PATCH] net: usb: Delete unnecessary checks before the macro call “dev_kfree_skb”
From: David Miller @ 2019-08-22 23:23 UTC (permalink / raw)
To: Markus.Elfring
Cc: linux-usb, netdev, gregkh, kstewart, petkan, swinslow, tglx,
linux-kernel, kernel-janitors
In-Reply-To: <425214be-355b-92c0-bc74-1d0ea899290f@web.de>
From: Markus Elfring <Markus.Elfring@web.de>
Date: Wed, 21 Aug 2019 22:24:16 +0200
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Wed, 21 Aug 2019 22:16:02 +0200
>
> The dev_kfree_skb() function performs also input parameter validation.
> Thus the test around the shown calls is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
Applied.
^ permalink raw reply
* Re: [PATCH] ethernet: Delete unnecessary checks before the macro call “dev_kfree_skb”
From: David Miller @ 2019-08-22 23:23 UTC (permalink / raw)
To: Markus.Elfring
Cc: netdev, linux-arm-kernel, linux-stm32, intel-wired-lan,
bcm-kernel-feedback-list, UNGLinuxDriver, alexandre.torgue,
alexios.zavras, allison, bryan.whitehead, claudiu.manoil, opendmb,
dougmill, f.fainelli, peppe.cavallaro, gregkh, jeffrey.t.kirsher,
opensource, jonathan.lemon, joabreu, kstewart, mcgrof,
mcoquelin.stm32, michael.heimpold, nico, ynezz, shannon.nelson,
stefan.wahren, swinslow, tglx, weiyongjun1, wsa+renesas,
yang.wei9, yuehaibing, zhongjiang, linux-kernel, kernel-janitors
In-Reply-To: <af1ae1cf-4a01-5e3a-edc2-058668487137@web.de>
From: Markus Elfring <Markus.Elfring@web.de>
Date: Thu, 22 Aug 2019 20:30:15 +0200
> From: Markus Elfring <elfring@users.sourceforge.net>
> Date: Thu, 22 Aug 2019 20:02:56 +0200
>
> The dev_kfree_skb() function performs also input parameter validation.
> Thus the test around the shown calls is not needed.
>
> This issue was detected by using the Coccinelle software.
>
> Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
Applied.
^ permalink raw reply
* Re: RFC: very rough draft of a bpf permission model
From: Alexei Starovoitov @ 2019-08-22 23:26 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Daniel Borkmann, Song Liu, Kees Cook, Networking, bpf,
Alexei Starovoitov, Kernel Team, Lorenz Bauer, Jann Horn, Greg KH,
Linux API, LSM List, Chenbo Feng
In-Reply-To: <CALCETrWU4xJh4UBg0BboCwdGrgj+dUShsH5ETpiRgEpXJTEfQA@mail.gmail.com>
On Thu, Aug 22, 2019 at 08:17:54AM -0700, Andy Lutomirski wrote:
> BPF security strawman, v0.1
>
> This is very rough. Most of this, especially the API details, needs
> work before it's ready to implement. The whole concept also needs
> review.
>
> = Goals =
>
> The overall goal is to make it possible to use eBPF without having
> what is effectively administrator access. For example, an eBPF user
> should not be able to directly tamper with other processes (unless
> this permission is explicitly granted) and should not be able to
> read or write other users' eBPF maps.
>
> It should be possible to use eBPF inside a user namespace without breaking
> the userns security model.
>
> Due to the risk of speculation attacks and such being carried out via
> eBPF, it should not become possible to use too much of eBPF without the
> administrator's permission. (NB: it is already possible to use
> *classic* BPF without any permission, and classic BPF is translated
> internally to eBPF, so this goal can only be met to a limited extent.)
agree with the goals.
> = Definitions =
>
> Global capability: A capability bit in the caller's effective mask, so
> long as the caller is in the root user namespace. Tasks in non-root
> user namespaces never have global capabilibies. This is what capable()
> checks.
>
> Namespace capability: A capability over a specific user namespace.
> Tasks in a user namespace have all the capabilities in their effective
> mask over their user namespace. A namespace capability generally
> indicates that the capability applies to the user namespace itself and
> to all non-user namespaces that live in the user namespace. For
> example, CAP_NET_ADMIN means that you can configure all networks
> namespaces in the current user namespace. This is what ns_capable()
> checks.
definitions make sense too.
> Anything that requires a global capability will not work in a non-root
> user namespace.
>
> = unprivileged_bpf_disabled =
>
> Nothing in here supercedes unprivileged_bpf_disabled. If
> unprivileged_bpf_disabled = 1, then these proposals should not allow anything
> that is disallowed today. The idea is to make unprivileged_bpf_disabled=0
> both safer and more useful.
... a bunch of new features skipped for brevity...
You're proposing all of the above in addition to CAP_BPF, right?
Otherwise I don't see how it addresses the use cases I kept
explaining for the last few weeks.
I don't mind additional features if people who propose them
actively help to maintain that new code and address inevitable
side channel issues in the new code.
But first things first.
Here is another example of use case that CAP_BPF is solving:
The daemon X is started by pid=1 and currently runs as root.
It loads a bunch of tracing progs and attaches them to kprobes
and tracepoints. It also loads cgroup-bpf progs and attaches them
to cgroups. All progs are collecting data about the system and
logging it for further analysis.
There can be different bugs (not security bugs) in the daemon.
Simple coding bugs, but due to processing running as root they
may make the system inoperable. There is a strong desire to
drop privileges for this daemon. Let it do all BPF things the
way it does today and drop root, since other operations do not
require root.
Essentially a bunch of daemons run as root only because
they need bpf. This tracing bpf is looking into kernel memory
and using bpf_probe_read. Clearly it's not _secure_. But it's _safe_.
The system is not going to crash because of BPF,
but it can easily crash because of simple coding bugs in the user
space bits of that daemon.
Flagging functions is not going to help this case.
bpf_probe_read is necessary.
pointer-to-integer-conversions is also necessary.
bypass hardening features is also necessary for speed,
since this data collection is 24/7.
cgroup.subtree_control idea can help some of it, but not all.
I still think that CAP_BPF is the best way to split this root privilege
universe into smaller 'bpf piece'. Just like CAP_NET_ADMIN splits
all of root into networking specific privileges.
Potentially we can go sysctl_perf_event_paranoid approach, but
it's less flexible, since it's single sysctl for the whole system.
Loading progs via FD instead of memory is something that android folks
proposed some time ago. The need is real. Whether it's going to be
loading via FD or some other form of signing the program is TBD.
imo this is orthogonal.
I hope I answered all points of your proposal.
^ permalink raw reply
* [pull request][net-next 0/8] Mellanox, mlx5 updates 2019-08-22
From: Saeed Mahameed @ 2019-08-22 23:35 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev@vger.kernel.org, Saeed Mahameed
Hi Dave,
This series provides some misc updates to mlx5 driver.
For more information please see tag log below.
Please pull and let me know if there is any problem.
Please note that the series starts with a merge of mlx5-next branch,
to resolve and avoid dependency with rdma tree.
Thanks,
Saeed.
---
The following changes since commit dc499cdf79f28a42cef0f1d62fe846090d14701a:
Merge branch 'mlx5-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux (2019-08-22 16:32:07 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux.git tags/mlx5-updates-2019-08-22
for you to fetch changes up to 9f7df106da11f5863e12283700138722bdc46c83:
net/mlx5e: Support TSO and TX checksum offloads for IP-in-IP tunnels (2019-08-22 16:32:15 -0700)
----------------------------------------------------------------
mlx5-updates-2019-08-22
Misc updates for mlx5e net device driver
1) Maxim and Tariq add the support for LAG TX port affinity distribution
When VF LAG is enabled, VFs netdevs will round-robin the TX affinity
of their tx queues among the different LAG ports.
2) Aya adds the support for ip-in-ip RSS.
3) Marina adds the support for ip-in-ip TX TSO and checksum offloads.
4) Moshe adds a device internal drop counter to mlx5 ethtool stats.
----------------------------------------------------------------
Aya Levin (2):
net/mlx5e: Change function's position to a more fitting file
net/mlx5e: Support RSS for IP-in-IP and IPv6 tunneled packets
Erez Alfasi (1):
net/mlx5e: ethtool, Fix a typo in WOL function names
Marina Varshaver (2):
net/mlx5e: Improve stateless offload capability check
net/mlx5e: Support TSO and TX checksum offloads for IP-in-IP tunnels
Maxim Mikityanskiy (1):
net/mlx5e: Support LAG TX port affinity distribution
Moshe Shemesh (1):
net/mlx5e: Add device out of buffer counter
Tariq Toukan (1):
net/mlx5e: Expose new function for TIS destroy loop
drivers/net/ethernet/mellanox/mlx5/core/en.h | 18 ++++--
drivers/net/ethernet/mellanox/mlx5/core/en/fs.h | 9 +++
.../net/ethernet/mellanox/mlx5/core/en_ethtool.c | 8 +--
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c | 50 +++++++++++++++
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 75 ++++++++++++++++------
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 9 +--
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c | 38 +++++++----
.../net/ethernet/mellanox/mlx5/core/ipoib/ipoib.c | 4 +-
.../ethernet/mellanox/mlx5/core/ipoib/ipoib_vlan.c | 6 +-
9 files changed, 163 insertions(+), 54 deletions(-)
^ permalink raw reply
* [net-next 1/8] net/mlx5e: ethtool, Fix a typo in WOL function names
From: Saeed Mahameed @ 2019-08-22 23:35 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev@vger.kernel.org, Erez Alfasi, Saeed Mahameed
In-Reply-To: <20190822233514.31252-1-saeedm@mellanox.com>
From: Erez Alfasi <ereza@mellanox.com>
Fix a typo in 'mlx5e_refomrat_wol_mode_mlx5_to_linux' and
'mlx5e_refomrat_wol_mode_linux_to_mlx5' function names:
"refomrat" -> "reformat".
Fixes: 928cfe8745a6 ("net/mlx5e: Wake On LAN support")
Signed-off-by: Erez Alfasi <ereza@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
index 7347d673f448..c5a9c20d7f00 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
@@ -1431,7 +1431,7 @@ static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev)
return ret;
}
-static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode)
+static __u32 mlx5e_reformat_wol_mode_mlx5_to_linux(u8 mode)
{
__u32 ret = 0;
@@ -1459,7 +1459,7 @@ static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode)
return ret;
}
-static u8 mlx5e_refomrat_wol_mode_linux_to_mlx5(__u32 mode)
+static u8 mlx5e_reformat_wol_mode_linux_to_mlx5(__u32 mode)
{
u8 ret = 0;
@@ -1505,7 +1505,7 @@ static void mlx5e_get_wol(struct net_device *netdev,
if (err)
return;
- wol->wolopts = mlx5e_refomrat_wol_mode_mlx5_to_linux(mlx5_wol_mode);
+ wol->wolopts = mlx5e_reformat_wol_mode_mlx5_to_linux(mlx5_wol_mode);
}
static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
@@ -1521,7 +1521,7 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
if (wol->wolopts & ~wol_supported)
return -EINVAL;
- mlx5_wol_mode = mlx5e_refomrat_wol_mode_linux_to_mlx5(wol->wolopts);
+ mlx5_wol_mode = mlx5e_reformat_wol_mode_linux_to_mlx5(wol->wolopts);
return mlx5_set_port_wol(mdev, mlx5_wol_mode);
}
--
2.21.0
^ permalink raw reply related
* [net-next 2/8] net/mlx5e: Expose new function for TIS destroy loop
From: Saeed Mahameed @ 2019-08-22 23:35 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev@vger.kernel.org, Tariq Toukan, Saeed Mahameed
In-Reply-To: <20190822233514.31252-1-saeedm@mellanox.com>
From: Tariq Toukan <tariqt@mellanox.com>
For better modularity and code sharing.
Function internal change to be introduced in the next patches.
Signed-off-by: Tariq Toukan <tariqt@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 +
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 13 +++++++++----
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 9 +++------
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index 446792799125..491c281416d0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -1107,6 +1107,7 @@ int mlx5e_create_tis(struct mlx5_core_dev *mdev, void *in, u32 *tisn);
void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn);
int mlx5e_create_tises(struct mlx5e_priv *priv);
+void mlx5e_destroy_tises(struct mlx5e_priv *priv);
int mlx5e_update_nic_rx(struct mlx5e_priv *priv);
void mlx5e_update_carrier(struct mlx5e_priv *priv);
int mlx5e_close(struct net_device *netdev);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index fa4bf2d4bcd4..d0cda5181ab4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3179,6 +3179,14 @@ void mlx5e_destroy_tis(struct mlx5_core_dev *mdev, u32 tisn)
mlx5_core_destroy_tis(mdev, tisn);
}
+void mlx5e_destroy_tises(struct mlx5e_priv *priv)
+{
+ int tc;
+
+ for (tc = 0; tc < priv->profile->max_tc; tc++)
+ mlx5e_destroy_tis(priv->mdev, priv->tisn[tc]);
+}
+
int mlx5e_create_tises(struct mlx5e_priv *priv)
{
int err;
@@ -3208,10 +3216,7 @@ int mlx5e_create_tises(struct mlx5e_priv *priv)
static void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv)
{
- int tc;
-
- for (tc = 0; tc < priv->profile->max_tc; tc++)
- mlx5e_destroy_tis(priv->mdev, priv->tisn[tc]);
+ mlx5e_destroy_tises(priv);
}
static void mlx5e_build_indir_tir_ctx_common(struct mlx5e_priv *priv,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 3c0d36b2b91c..b94fc3a35e10 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -1618,7 +1618,7 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
{
struct mlx5e_rep_priv *rpriv = priv->ppriv;
struct mlx5_rep_uplink_priv *uplink_priv;
- int tc, err;
+ int err;
err = mlx5e_create_tises(priv);
if (err) {
@@ -1654,18 +1654,15 @@ static int mlx5e_init_rep_tx(struct mlx5e_priv *priv)
tc_esw_cleanup:
mlx5e_tc_esw_cleanup(&uplink_priv->tc_ht);
destroy_tises:
- for (tc = 0; tc < priv->profile->max_tc; tc++)
- mlx5e_destroy_tis(priv->mdev, priv->tisn[tc]);
+ mlx5e_destroy_tises(priv);
return err;
}
static void mlx5e_cleanup_rep_tx(struct mlx5e_priv *priv)
{
struct mlx5e_rep_priv *rpriv = priv->ppriv;
- int tc;
- for (tc = 0; tc < priv->profile->max_tc; tc++)
- mlx5e_destroy_tis(priv->mdev, priv->tisn[tc]);
+ mlx5e_destroy_tises(priv);
if (rpriv->rep->vport == MLX5_VPORT_UPLINK) {
/* clean indirect TC block notifications */
--
2.21.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