* Re: [PATCH 2.6.25 3/9] SCTP: Add the handling of "Set Primary IP Address" parameter to INIT
From: David Miller @ 2007-12-20 22:10 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: netdev, lksctp-developers
In-Reply-To: <1197927169-5106-4-git-send-email-vladislav.yasevich@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Mon, 17 Dec 2007 16:32:43 -0500
> The ADD-IP "Set Primary IP Address" parameter is allowed in the
> INIT/INIT-ACK exchange. Allow processing of this parameter during
> the INIT/INIT-ACK.
>
> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied.
^ permalink raw reply
* Re: [PATCH 2.6.25 4/9] SCTP: Update association lookup to look at ASCONF chunks as well
From: David Miller @ 2007-12-20 22:10 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: netdev, lksctp-developers
In-Reply-To: <1197927169-5106-5-git-send-email-vladislav.yasevich@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Mon, 17 Dec 2007 16:32:44 -0500
> ADD-IP draft section 5.2 specifies that if an association can not
> be found using the source and destination of the IP packet,
> then, if the packet contains ASCONF chunks, the Address Parameter
> TLV should be used to lookup an association.
>
> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied.
^ permalink raw reply
* Re: [PATCH 2.6.25 5/9] SCTP: ADD-IP updates the states where ASCONFs can be sent
From: David Miller @ 2007-12-20 22:11 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: netdev, lksctp-developers
In-Reply-To: <1197927169-5106-6-git-send-email-vladislav.yasevich@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Mon, 17 Dec 2007 16:32:45 -0500
> C4) Both ASCONF and ASCONF-ACK Chunks MUST NOT be sent in any SCTP
> state except ESTABLISHED, SHUTDOWN-PENDING, SHUTDOWN-RECEIVED,
> and SHUTDOWN-SENT.
>
> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied.
^ permalink raw reply
* Re: [PATCH 2.6.25 6/9] SCTP: Update ASCONF processing to conform to spec.
From: David Miller @ 2007-12-20 22:11 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: netdev, lksctp-developers
In-Reply-To: <1197927169-5106-7-git-send-email-vladislav.yasevich@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Mon, 17 Dec 2007 16:32:46 -0500
> The processing of the ASCONF chunks has changed a lot in the
> spec. New items are:
> 1. A list of ASCONF-ACK chunks is now cached
> 2. The source of the packet is used in response.
> 3. New handling for unexpect ASCONF chunks.
>
> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied.
^ permalink raw reply
* Re: [PATCH 2.6.25 8/9] SCTP: Implement ADD-IP special case processing for ABORT chunk
From: David Miller @ 2007-12-20 22:13 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: netdev, lksctp-developers
In-Reply-To: <1197927169-5106-9-git-send-email-vladislav.yasevich@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Mon, 17 Dec 2007 16:32:48 -0500
> ADD-IP spec has a special case for processing ABORTs:
> F4) ... One special consideration is that ABORT
> Chunks arriving destined to the IP address being deleted MUST be
> ignored (see Section 5.3.1 for further details).
>
> Check if the address we received on is in the DEL state, and if
> so, ignore the ABORT.
>
> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied.
^ permalink raw reply
* Re: [PATCH 2.6.25 9/9] SCTP: Follow Add-IP security consideratiosn wrt INIT/INIT-ACK
From: David Miller @ 2007-12-20 22:13 UTC (permalink / raw)
To: vladislav.yasevich; +Cc: netdev, lksctp-developers
In-Reply-To: <1197927169-5106-10-git-send-email-vladislav.yasevich@hp.com>
From: Vlad Yasevich <vladislav.yasevich@hp.com>
Date: Mon, 17 Dec 2007 16:32:49 -0500
> The Security Considerations section of RFC 5061 has the following
> text:
>
> If an SCTP endpoint that supports this extension receives an INIT
> that indicates that the peer supports the ASCONF extension but does
> NOT support the [RFC4895] extension, the receiver of such an INIT
> MUST send an ABORT in response. Note that an implementation is
> allowed to silently discard such an INIT as an option as well, but
> under NO circumstance is an implementation allowed to proceed with
> the association setup by sending an INIT-ACK in response.
>
> An implementation that receives an INIT-ACK that indicates that the
> peer does not support the [RFC4895] extension MUST NOT send the
> COOKIE-ECHO to establish the association. Instead, the
> implementation MUST discard the INIT-ACK and report to the upper-
> layer user that an association cannot be established destroying the
> Transmission Control Block (TCB).
>
> Follow the recomendations.
>
> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Applied, thanks.
^ permalink raw reply
* Re: [RFC PATCH] LSM: Add inet_sys_snd_skb() LSM hook
From: James Morris @ 2007-12-20 22:22 UTC (permalink / raw)
To: Paul Moore; +Cc: netdev, David S. Miller
In-Reply-To: <20071219222100.1626.38321.stgit@flek.americas.hpqcorp.net>
On Wed, 19 Dec 2007, Paul Moore wrote:
> Add an inet_sys_snd_skb() LSM hook to allow the LSM to provide packet level
> access control for all outbound packets. Using the existing postroute_last
> netfilter hook turns out to be problematic as it is can be invoked multiple
> times for a single packet, e.g. individual IPsec transforms, adding unwanted
> overhead and complicating the security policy.
I'm fine to ack this from a security pov -- any objections on the
networking side?
- James
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH 1/3] XFRM: Assorted IPsec fixups
From: James Morris @ 2007-12-20 22:25 UTC (permalink / raw)
To: Paul Moore; +Cc: netdev, linux-audit
In-Reply-To: <20071220214219.12122.57208.stgit@flek.lan>
On Thu, 20 Dec 2007, Paul Moore wrote:
> This patch fixes a number of small but potentially troublesome things in the
> XFRM/IPsec code:
>
> * Use the 'audit_enabled' variable already in include/linux/audit.h
> Removed the need for extern declarations local to each XFRM audit fuction
>
> * Convert 'sid' to 'secid' everywhere we can
> The 'sid' name is specific to SELinux, 'secid' is the common naming
> convention used by the kernel when refering to tokenized LSM labels,
> unfortunately we have to leave 'ctx_sid' in 'struct xfrm_sec_ctx' otherwise
> we risk breaking userspace
>
> * Convert address display to use standard NIP* macros
> Similar to what was recently done with the SPD audit code, this also also
> includes the removal of some unnecessary memcpy() calls
>
> * Move common code to xfrm_audit_common_stateinfo()
> Code consolidation from the "less is more" book on software development
>
> * Proper spacing around commas in function arguments
> Minor style tweak since I was already touching the code
>
> Signed-off-by: Paul Moore <paul.moore@hp.com>
Acked-by: James Morris <jmorris@namei.org>
> ---
>
> include/net/xfrm.h | 14 ++++++-------
> net/xfrm/xfrm_policy.c | 15 ++++++--------
> net/xfrm/xfrm_state.c | 53 ++++++++++++++++++++----------------------------
> 3 files changed, 36 insertions(+), 46 deletions(-)
>
> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
> index 32b99e2..ac6cf09 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -548,7 +548,7 @@ struct xfrm_audit
> };
>
> #ifdef CONFIG_AUDITSYSCALL
> -static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 sid)
> +static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 secid)
> {
> struct audit_buffer *audit_buf = NULL;
> char *secctx;
> @@ -561,8 +561,8 @@ static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 sid)
>
> audit_log_format(audit_buf, "auid=%u", auid);
>
> - if (sid != 0 &&
> - security_secid_to_secctx(sid, &secctx, &secctx_len) == 0) {
> + if (secid != 0 &&
> + security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) {
> audit_log_format(audit_buf, " subj=%s", secctx);
> security_release_secctx(secctx, secctx_len);
> } else
> @@ -571,13 +571,13 @@ static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 sid)
> }
>
> extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
> - u32 auid, u32 sid);
> + u32 auid, u32 secid);
> extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
> - u32 auid, u32 sid);
> + u32 auid, u32 secid);
> extern void xfrm_audit_state_add(struct xfrm_state *x, int result,
> - u32 auid, u32 sid);
> + u32 auid, u32 secid);
> extern void xfrm_audit_state_delete(struct xfrm_state *x, int result,
> - u32 auid, u32 sid);
> + u32 auid, u32 secid);
> #else
> #define xfrm_audit_policy_add(x, r, a, s) do { ; } while (0)
> #define xfrm_audit_policy_delete(x, r, a, s) do { ; } while (0)
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index d2084b1..c8f0656 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -24,6 +24,7 @@
> #include <linux/netfilter.h>
> #include <linux/module.h>
> #include <linux/cache.h>
> +#include <linux/audit.h>
> #include <net/dst.h>
> #include <net/xfrm.h>
> #include <net/ip.h>
> @@ -2317,15 +2318,14 @@ static inline void xfrm_audit_common_policyinfo(struct xfrm_policy *xp,
> }
> }
>
> -void
> -xfrm_audit_policy_add(struct xfrm_policy *xp, int result, u32 auid, u32 sid)
> +void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
> + u32 auid, u32 secid)
> {
> struct audit_buffer *audit_buf;
> - extern int audit_enabled;
>
> if (audit_enabled == 0)
> return;
> - audit_buf = xfrm_audit_start(sid, auid);
> + audit_buf = xfrm_audit_start(auid, secid);
> if (audit_buf == NULL)
> return;
> audit_log_format(audit_buf, " op=SPD-add res=%u", result);
> @@ -2334,15 +2334,14 @@ xfrm_audit_policy_add(struct xfrm_policy *xp, int result, u32 auid, u32 sid)
> }
> EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
>
> -void
> -xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, u32 auid, u32 sid)
> +void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
> + u32 auid, u32 secid)
> {
> struct audit_buffer *audit_buf;
> - extern int audit_enabled;
>
> if (audit_enabled == 0)
> return;
> - audit_buf = xfrm_audit_start(sid, auid);
> + audit_buf = xfrm_audit_start(auid, secid);
> if (audit_buf == NULL)
> return;
> audit_log_format(audit_buf, " op=SPD-delete res=%u", result);
> diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
> index 95df01c..dd38e6f 100644
> --- a/net/xfrm/xfrm_state.c
> +++ b/net/xfrm/xfrm_state.c
> @@ -19,6 +19,7 @@
> #include <linux/ipsec.h>
> #include <linux/module.h>
> #include <linux/cache.h>
> +#include <linux/audit.h>
> #include <asm/uaccess.h>
>
> #include "xfrm_hash.h"
> @@ -1996,69 +1997,59 @@ void __init xfrm_state_init(void)
> static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x,
> struct audit_buffer *audit_buf)
> {
> - if (x->security)
> + struct xfrm_sec_ctx *ctx = x->security;
> + u32 spi = ntohl(x->id.spi);
> +
> + if (ctx)
> audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s",
> - x->security->ctx_alg, x->security->ctx_doi,
> - x->security->ctx_str);
> + ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str);
>
> switch(x->props.family) {
> case AF_INET:
> - audit_log_format(audit_buf, " src=%u.%u.%u.%u dst=%u.%u.%u.%u",
> + audit_log_format(audit_buf,
> + " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
> NIPQUAD(x->props.saddr.a4),
> NIPQUAD(x->id.daddr.a4));
> break;
> case AF_INET6:
> - {
> - struct in6_addr saddr6, daddr6;
> -
> - memcpy(&saddr6, x->props.saddr.a6,
> - sizeof(struct in6_addr));
> - memcpy(&daddr6, x->id.daddr.a6,
> - sizeof(struct in6_addr));
> - audit_log_format(audit_buf,
> - " src=" NIP6_FMT " dst=" NIP6_FMT,
> - NIP6(saddr6), NIP6(daddr6));
> - }
> + audit_log_format(audit_buf,
> + " src=" NIP6_FMT " dst=" NIP6_FMT,
> + NIP6(*(struct in6_addr *)x->props.saddr.a6),
> + NIP6(*(struct in6_addr *)x->id.daddr.a6));
> break;
> }
> +
> + audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
> }
>
> -void
> -xfrm_audit_state_add(struct xfrm_state *x, int result, u32 auid, u32 sid)
> +void xfrm_audit_state_add(struct xfrm_state *x, int result,
> + u32 auid, u32 secid)
> {
> struct audit_buffer *audit_buf;
> - u32 spi;
> - extern int audit_enabled;
>
> if (audit_enabled == 0)
> return;
> - audit_buf = xfrm_audit_start(sid, auid);
> + audit_buf = xfrm_audit_start(auid, secid);
> if (audit_buf == NULL)
> return;
> - audit_log_format(audit_buf, " op=SAD-add res=%u",result);
> + audit_log_format(audit_buf, " op=SAD-add res=%u", result);
> xfrm_audit_common_stateinfo(x, audit_buf);
> - spi = ntohl(x->id.spi);
> - audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
> audit_log_end(audit_buf);
> }
> EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
>
> -void
> -xfrm_audit_state_delete(struct xfrm_state *x, int result, u32 auid, u32 sid)
> +void xfrm_audit_state_delete(struct xfrm_state *x, int result,
> + u32 auid, u32 secid)
> {
> struct audit_buffer *audit_buf;
> - u32 spi;
> - extern int audit_enabled;
>
> if (audit_enabled == 0)
> return;
> - audit_buf = xfrm_audit_start(sid, auid);
> + audit_buf = xfrm_audit_start(auid, secid);
> if (audit_buf == NULL)
> return;
> - audit_log_format(audit_buf, " op=SAD-delete res=%u",result);
> + audit_log_format(audit_buf, " op=SAD-delete res=%u", result);
> xfrm_audit_common_stateinfo(x, audit_buf);
> - spi = ntohl(x->id.spi);
> - audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
> audit_log_end(audit_buf);
> }
> EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH 2/3] XFRM: RFC4303 compliant auditing
From: James Morris @ 2007-12-20 22:27 UTC (permalink / raw)
To: Paul Moore; +Cc: netdev, linux-audit
In-Reply-To: <20071220214225.12122.48656.stgit@flek.lan>
On Thu, 20 Dec 2007, Paul Moore wrote:
> This patch adds a number of new IPsec audit events to meet the auditing
> requirements of RFC4303. This includes audit hooks for the following events:
>
> * Could not find a valid SA [sections 2.1, 3.4.2]
> . xfrm_audit_state_notfound()
> . xfrm_audit_state_notfound_simple()
>
> * Sequence number overflow [section 3.3.3]
> . xfrm_audit_state_replay_overflow()
>
> * Replayed packet [section 3.4.3]
> . xfrm_audit_state_replay()
>
> * Integrity check failure [sections 3.4.4.1, 3.4.4.2]
> . xfrm_audit_state_icvfail()
>
> While RFC4304 deals only with ESP most of the changes in this patch apply to
> IPsec in general, i.e. both AH and ESP. The one case, integrity check
> failure, where ESP specific code had to be modified the same was done to the
> AH code for the sake of consistency.
>
> Signed-off-by: Paul Moore <paul.moore@hp.com>
Acked-by: James Morris <jmorris@namei.org>
> ---
>
> include/net/xfrm.h | 33 ++++++++--
> net/ipv4/ah4.c | 4 +
> net/ipv4/esp4.c | 1
> net/ipv6/ah6.c | 2 -
> net/ipv6/esp6.c | 1
> net/ipv6/xfrm6_input.c | 4 +
> net/xfrm/xfrm_input.c | 6 +-
> net/xfrm/xfrm_output.c | 2 +
> net/xfrm/xfrm_policy.c | 14 ++--
> net/xfrm/xfrm_state.c | 153 +++++++++++++++++++++++++++++++++++++++++++-----
> 10 files changed, 184 insertions(+), 36 deletions(-)
>
> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
> index ac6cf09..941d5cd 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -548,26 +548,33 @@ struct xfrm_audit
> };
>
> #ifdef CONFIG_AUDITSYSCALL
> -static inline struct audit_buffer *xfrm_audit_start(u32 auid, u32 secid)
> +static inline struct audit_buffer *xfrm_audit_start(const char *op)
> {
> struct audit_buffer *audit_buf = NULL;
> - char *secctx;
> - u32 secctx_len;
>
> + if (audit_enabled == 0)
> + return NULL;
> audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC,
> - AUDIT_MAC_IPSEC_EVENT);
> + AUDIT_MAC_IPSEC_EVENT);
> if (audit_buf == NULL)
> return NULL;
> + audit_log_format(audit_buf, "op=%s", op);
> + return audit_buf;
> +}
>
> - audit_log_format(audit_buf, "auid=%u", auid);
> +static inline void xfrm_audit_helper_usrinfo(u32 auid, u32 secid,
> + struct audit_buffer *audit_buf)
> +{
> + char *secctx;
> + u32 secctx_len;
>
> + audit_log_format(audit_buf, " auid=%u", auid);
> if (secid != 0 &&
> security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) {
> audit_log_format(audit_buf, " subj=%s", secctx);
> security_release_secctx(secctx, secctx_len);
> } else
> audit_log_task_context(audit_buf);
> - return audit_buf;
> }
>
> extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
> @@ -578,11 +585,22 @@ extern void xfrm_audit_state_add(struct xfrm_state *x, int result,
> u32 auid, u32 secid);
> extern void xfrm_audit_state_delete(struct xfrm_state *x, int result,
> u32 auid, u32 secid);
> +extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
> + struct sk_buff *skb);
> +extern void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family);
> +extern void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
> + __be32 net_spi, __be32 net_seq);
> +extern void xfrm_audit_state_icvfail(struct xfrm_state *x,
> + struct sk_buff *skb, u8 proto);
> #else
> #define xfrm_audit_policy_add(x, r, a, s) do { ; } while (0)
> #define xfrm_audit_policy_delete(x, r, a, s) do { ; } while (0)
> #define xfrm_audit_state_add(x, r, a, s) do { ; } while (0)
> #define xfrm_audit_state_delete(x, r, a, s) do { ; } while (0)
> +#define xfrm_audit_state_replay_overflow(x, s) do { ; } while (0)
> +#define xfrm_audit_state_notfound_simple(s, f) do { ; } while (0)
> +#define xfrm_audit_state_notfound(s, f, sp, sq) do { ; } while (0)
> +#define xfrm_audit_state_icvfail(x, s, p) do { ; } while (0)
> #endif /* CONFIG_AUDITSYSCALL */
>
> static inline void xfrm_pol_hold(struct xfrm_policy *policy)
> @@ -1193,7 +1211,8 @@ extern int xfrm_state_delete(struct xfrm_state *x);
> extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info);
> extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si);
> extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si);
> -extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq);
> +extern int xfrm_replay_check(struct xfrm_state *x,
> + struct sk_buff *skb, __be32 seq);
> extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq);
> extern void xfrm_replay_notify(struct xfrm_state *x, int event);
> extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
> diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
> index d76803a..ec8de0a 100644
> --- a/net/ipv4/ah4.c
> +++ b/net/ipv4/ah4.c
> @@ -179,8 +179,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
> err = ah_mac_digest(ahp, skb, ah->auth_data);
> if (err)
> goto unlock;
> - if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len))
> + if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
> + xfrm_audit_state_icvfail(x, skb, IPPROTO_AH);
> err = -EBADMSG;
> + }
> }
> unlock:
> spin_unlock(&x->lock);
> diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
> index 28ea5c7..b334c76 100644
> --- a/net/ipv4/esp4.c
> +++ b/net/ipv4/esp4.c
> @@ -191,6 +191,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
> BUG();
>
> if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
> + xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP);
> err = -EBADMSG;
> goto unlock;
> }
> diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
> index 1b51d1e..2d32772 100644
> --- a/net/ipv6/ah6.c
> +++ b/net/ipv6/ah6.c
> @@ -381,7 +381,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
> if (err)
> goto unlock;
> if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {
> - LIMIT_NETDEBUG(KERN_WARNING "ipsec ah authentication error\n");
> + xfrm_audit_state_icvfail(x, skb, IPPROTO_AH);
> err = -EBADMSG;
> }
> }
> diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
> index 5bd5292..e10f10b 100644
> --- a/net/ipv6/esp6.c
> +++ b/net/ipv6/esp6.c
> @@ -186,6 +186,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
> BUG();
>
> if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
> + xfrm_audit_state_icvfail(x, skb, IPPROTO_ESP);
> ret = -EBADMSG;
> goto unlock;
> }
> diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
> index 74f3aac..08b850a 100644
> --- a/net/ipv6/xfrm6_input.c
> +++ b/net/ipv6/xfrm6_input.c
> @@ -136,8 +136,10 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
> break;
> }
>
> - if (!xfrm_vec_one)
> + if (!xfrm_vec_one) {
> + xfrm_audit_state_notfound_simple(skb, AF_INET6);
> goto drop;
> + }
>
> /* Allocate new secpath or COW existing one. */
> if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
> diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
> index 8624cbd..87e1aac 100644
> --- a/net/xfrm/xfrm_input.c
> +++ b/net/xfrm/xfrm_input.c
> @@ -139,8 +139,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
> goto drop;
>
> x = xfrm_state_lookup(daddr, spi, nexthdr, family);
> - if (x == NULL)
> + if (x == NULL) {
> + xfrm_audit_state_notfound(skb, family, spi, seq);
> goto drop;
> + }
>
> skb->sp->xvec[skb->sp->len++] = x;
>
> @@ -151,7 +153,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
> if ((x->encap ? x->encap->encap_type : 0) != encap_type)
> goto drop_unlock;
>
> - if (x->props.replay_window && xfrm_replay_check(x, seq))
> + if (x->props.replay_window && xfrm_replay_check(x, skb, seq))
> goto drop_unlock;
>
> if (xfrm_state_check_expire(x))
> diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
> index 26fa0cb..eb3333b 100644
> --- a/net/xfrm/xfrm_output.c
> +++ b/net/xfrm/xfrm_output.c
> @@ -57,6 +57,8 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
>
> if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
> XFRM_SKB_CB(skb)->seq = ++x->replay.oseq;
> + if (unlikely(x->replay.oseq == 0))
> + xfrm_audit_state_replay_overflow(x, skb);
> if (xfrm_aevent_is_on())
> xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
> }
> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index c8f0656..97cebfe 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -2323,12 +2323,11 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
> {
> struct audit_buffer *audit_buf;
>
> - if (audit_enabled == 0)
> - return;
> - audit_buf = xfrm_audit_start(auid, secid);
> + audit_buf = xfrm_audit_start("SPD-add");
> if (audit_buf == NULL)
> return;
> - audit_log_format(audit_buf, " op=SPD-add res=%u", result);
> + xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
> + audit_log_format(audit_buf, " res=%u", result);
> xfrm_audit_common_policyinfo(xp, audit_buf);
> audit_log_end(audit_buf);
> }
> @@ -2339,12 +2338,11 @@ void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
> {
> struct audit_buffer *audit_buf;
>
> - if (audit_enabled == 0)
> - return;
> - audit_buf = xfrm_audit_start(auid, secid);
> + audit_buf = xfrm_audit_start("SPD-delete");
> if (audit_buf == NULL)
> return;
> - audit_log_format(audit_buf, " op=SPD-delete res=%u", result);
> + xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
> + audit_log_format(audit_buf, " res=%u", result);
> xfrm_audit_common_policyinfo(xp, audit_buf);
> audit_log_end(audit_buf);
> }
> diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
> index dd38e6f..1f00aeb 100644
> --- a/net/xfrm/xfrm_state.c
> +++ b/net/xfrm/xfrm_state.c
> @@ -61,6 +61,13 @@ static unsigned int xfrm_state_genid;
> static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
> static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
>
> +#ifdef CONFIG_AUDITSYSCALL
> +static void xfrm_audit_state_replay(struct xfrm_state *x,
> + struct sk_buff *skb, __be32 net_seq);
> +#else
> +#define xfrm_audit_state_replay(x, s, sq) do { ; } while (0)
> +#endif /* CONFIG_AUDITSYSCALL */
> +
> static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
> xfrm_address_t *saddr,
> u32 reqid,
> @@ -1609,13 +1616,14 @@ static void xfrm_replay_timer_handler(unsigned long data)
> spin_unlock(&x->lock);
> }
>
> -int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
> +int xfrm_replay_check(struct xfrm_state *x,
> + struct sk_buff *skb, __be32 net_seq)
> {
> u32 diff;
> u32 seq = ntohl(net_seq);
>
> if (unlikely(seq == 0))
> - return -EINVAL;
> + goto err;
>
> if (likely(seq > x->replay.seq))
> return 0;
> @@ -1624,14 +1632,18 @@ int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
> if (diff >= min_t(unsigned int, x->props.replay_window,
> sizeof(x->replay.bitmap) * 8)) {
> x->stats.replay_window++;
> - return -EINVAL;
> + goto err;
> }
>
> if (x->replay.bitmap & (1U << diff)) {
> x->stats.replay++;
> - return -EINVAL;
> + goto err;
> }
> return 0;
> +
> +err:
> + xfrm_audit_state_replay(x, skb, net_seq);
> + return -EINVAL;
> }
> EXPORT_SYMBOL(xfrm_replay_check);
>
> @@ -1994,8 +2006,8 @@ void __init xfrm_state_init(void)
> }
>
> #ifdef CONFIG_AUDITSYSCALL
> -static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x,
> - struct audit_buffer *audit_buf)
> +static inline void xfrm_audit_helper_sainfo(struct xfrm_state *x,
> + struct audit_buffer *audit_buf)
> {
> struct xfrm_sec_ctx *ctx = x->security;
> u32 spi = ntohl(x->id.spi);
> @@ -2022,18 +2034,45 @@ static inline void xfrm_audit_common_stateinfo(struct xfrm_state *x,
> audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
> }
>
> +static inline void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family,
> + struct audit_buffer *audit_buf)
> +{
> + struct iphdr *iph4;
> + struct ipv6hdr *iph6;
> +
> + switch (family) {
> + case AF_INET:
> + iph4 = ip_hdr(skb);
> + audit_log_format(audit_buf,
> + " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT,
> + NIPQUAD(iph4->saddr),
> + NIPQUAD(iph4->daddr));
> + break;
> + case AF_INET6:
> + iph6 = ipv6_hdr(skb);
> + audit_log_format(audit_buf,
> + " src=" NIP6_FMT " dst=" NIP6_FMT
> + " flowlbl=0x%x%x%x",
> + NIP6(iph6->saddr),
> + NIP6(iph6->daddr),
> + iph6->flow_lbl[0] & 0x0f,
> + iph6->flow_lbl[1],
> + iph6->flow_lbl[2]);
> + break;
> + }
> +}
> +
> void xfrm_audit_state_add(struct xfrm_state *x, int result,
> u32 auid, u32 secid)
> {
> struct audit_buffer *audit_buf;
>
> - if (audit_enabled == 0)
> - return;
> - audit_buf = xfrm_audit_start(auid, secid);
> + audit_buf = xfrm_audit_start("SAD-add");
> if (audit_buf == NULL)
> return;
> - audit_log_format(audit_buf, " op=SAD-add res=%u", result);
> - xfrm_audit_common_stateinfo(x, audit_buf);
> + xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
> + xfrm_audit_helper_sainfo(x, audit_buf);
> + audit_log_format(audit_buf, " res=%u", result);
> audit_log_end(audit_buf);
> }
> EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
> @@ -2043,14 +2082,96 @@ void xfrm_audit_state_delete(struct xfrm_state *x, int result,
> {
> struct audit_buffer *audit_buf;
>
> - if (audit_enabled == 0)
> - return;
> - audit_buf = xfrm_audit_start(auid, secid);
> + audit_buf = xfrm_audit_start("SAD-delete");
> if (audit_buf == NULL)
> return;
> - audit_log_format(audit_buf, " op=SAD-delete res=%u", result);
> - xfrm_audit_common_stateinfo(x, audit_buf);
> + xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
> + xfrm_audit_helper_sainfo(x, audit_buf);
> + audit_log_format(audit_buf, " res=%u", result);
> audit_log_end(audit_buf);
> }
> EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);
> +
> +void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
> + struct sk_buff *skb)
> +{
> + struct audit_buffer *audit_buf;
> + u32 spi;
> +
> + audit_buf = xfrm_audit_start("SA-replay-overflow");
> + if (audit_buf == NULL)
> + return;
> + xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
> + /* don't record the sequence number because it's inherent in this kind
> + * of audit message */
> + spi = ntohl(x->id.spi);
> + audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi);
> + audit_log_end(audit_buf);
> +}
> +EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow);
> +
> +static void xfrm_audit_state_replay(struct xfrm_state *x,
> + struct sk_buff *skb, __be32 net_seq)
> +{
> + struct audit_buffer *audit_buf;
> + u32 spi;
> +
> + audit_buf = xfrm_audit_start("SA-replayed-pkt");
> + if (audit_buf == NULL)
> + return;
> + xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
> + spi = ntohl(x->id.spi);
> + audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
> + spi, spi, ntohl(net_seq));
> + audit_log_end(audit_buf);
> +}
> +
> +void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family)
> +{
> + struct audit_buffer *audit_buf;
> +
> + audit_buf = xfrm_audit_start("SA-notfound");
> + if (audit_buf == NULL)
> + return;
> + xfrm_audit_helper_pktinfo(skb, family, audit_buf);
> + audit_log_end(audit_buf);
> +}
> +EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple);
> +
> +void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
> + __be32 net_spi, __be32 net_seq)
> +{
> + struct audit_buffer *audit_buf;
> + u32 spi;
> +
> + audit_buf = xfrm_audit_start("SA-notfound");
> + if (audit_buf == NULL)
> + return;
> + xfrm_audit_helper_pktinfo(skb, family, audit_buf);
> + spi = ntohl(net_spi);
> + audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
> + spi, spi, ntohl(net_seq));
> + audit_log_end(audit_buf);
> +}
> +EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound);
> +
> +void xfrm_audit_state_icvfail(struct xfrm_state *x,
> + struct sk_buff *skb, u8 proto)
> +{
> + struct audit_buffer *audit_buf;
> + __be32 net_spi;
> + __be32 net_seq;
> +
> + audit_buf = xfrm_audit_start("SA-icv-failure");
> + if (audit_buf == NULL)
> + return;
> + xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf);
> + if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) {
> + u32 spi = ntohl(net_spi);
> + audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u",
> + spi, spi, ntohl(net_seq));
> + }
> + audit_log_end(audit_buf);
> +}
> +EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail);
> #endif /* CONFIG_AUDITSYSCALL */
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH 3/3] XFRM: Drop packets when replay counter would overflow
From: James Morris @ 2007-12-20 22:28 UTC (permalink / raw)
To: Paul Moore; +Cc: netdev, linux-audit
In-Reply-To: <20071220214230.12122.77900.stgit@flek.lan>
On Thu, 20 Dec 2007, Paul Moore wrote:
> According to RFC4303, section 3.3.3 we need to drop outgoing packets which
> cause the replay counter to overflow:
>
> 3.3.3. Sequence Number Generation
>
> The sender's counter is initialized to 0 when an SA is established.
> The sender increments the sequence number (or ESN) counter for this
> SA and inserts the low-order 32 bits of the value into the Sequence
> Number field. Thus, the first packet sent using a given SA will
> contain a sequence number of 1.
>
> If anti-replay is enabled (the default), the sender checks to ensure
> that the counter has not cycled before inserting the new value in the
> Sequence Number field. In other words, the sender MUST NOT send a
> packet on an SA if doing so would cause the sequence number to cycle.
> An attempt to transmit a packet that would result in sequence number
> overflow is an auditable event. The audit log entry for this event
> SHOULD include the SPI value, current date/time, Source Address,
> Destination Address, and (in IPv6) the cleartext Flow ID.
>
> Signed-off-by: Paul Moore <paul.moore@hp.com>
Acked-by: James Morris <jmorris@namei.org>
> ---
>
> net/xfrm/xfrm_output.c | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
>
> diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
> index eb3333b..284eeef 100644
> --- a/net/xfrm/xfrm_output.c
> +++ b/net/xfrm/xfrm_output.c
> @@ -57,8 +57,11 @@ static int xfrm_output_one(struct sk_buff *skb, int err)
>
> if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
> XFRM_SKB_CB(skb)->seq = ++x->replay.oseq;
> - if (unlikely(x->replay.oseq == 0))
> + if (unlikely(x->replay.oseq == 0)) {
> + x->replay.oseq--;
> xfrm_audit_state_replay_overflow(x, skb);
> + goto error;
> + }
> if (xfrm_aevent_is_on())
> xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
> }
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH] NET: Fix function put_cmsg() which may cause usr application memory overflow
From: David Miller @ 2007-12-20 22:39 UTC (permalink / raw)
To: yjwei; +Cc: netdev
In-Reply-To: <4767665D.20300@cn.fujitsu.com>
From: Wei Yongjun <yjwei@cn.fujitsu.com>
Date: Tue, 18 Dec 2007 15:19:09 +0900
> When used function put_cmsg() to copy kernel information to user
> application memory, if the memory length given by user application is
> not enough, by the bad length calculate of msg.msg_controllen,
> put_cmsg() function may cause the msg.msg_controllen to be a large
> value, such as 0xFFFFFFF0, so the following put_cmsg() can also write
> data to usr application memory even usr has no valid memory to store
> this. This may cause usr application memory overflow.
...
> The same promble exists in put_cmsg_compat(). This patch can fix this
> problem.
>
> Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Thank you for fixing this bug, patch applied.
put_cmsg() is a confusing function, it takes a while to understand
what it is trying to accomplish. And this explains why this bug
lived for so long.
Each CMSG entry has to be aligned, but put_cmsg() will allow to
put the full final message into the CMSG area if there is enough
room to fit the message without the added alignment.
So, with Wei's fix, we now have:
int cmlen = CMSG_LEN(len);
...
if (msg->msg_controllen < cmlen) {
msg->msg_flags |= MSG_CTRUNC;
cmlen = msg->msg_controllen;
}
...
if (copy_to_user(cm, &cmhdr, sizeof cmhdr))
goto out;
if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr)))
goto out;
cmlen = CMSG_SPACE(len);
if (msg->msg_controllen < cmlen)
cmlen = msg->msg_controllen;
msg->msg_control += cmlen;
msg->msg_controllen -= cmlen;
...
which I think finally implements the intended behavior
accurately.
^ permalink raw reply
* Re: Please pull 'upstream-davem' branch of wireless-2.6
From: John W. Linville @ 2007-12-20 22:38 UTC (permalink / raw)
To: davem; +Cc: netdev, linux-wireless
In-Reply-To: <20071220155321.GF3139@tuxdriver.com>
On Thu, Dec 20, 2007 at 10:53:21AM -0500, John W. Linville wrote:
> These are destined for 2.6.25. The patches fall mostly into two
> categories: a new rate control algorithm for mac80211, and some
> cfg80211 enhancements (including mac80211 patches to use them).
> mac80211: make PID rate control algorithm the default
This patch is busted. I was mistaken about its readiness --
I apologize. Don't pull if you haven't already.
We are actively working on fixing/replacing it.
Thanks for your patience!
John
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply
* [PATCH 0/8] tg3: Flow Control Modifications
From: Matt Carlson @ 2007-12-20 23:02 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patchset modifies the driver to accept changes in flow control
settings via ethtool.
--
========================================================================
Matt Carlson 5300 California Ave
Senior Software Engineer Irvine, CA 92617
Broadcom (949) 926-6341
^ permalink raw reply
* [PATCH 1/8] tg3: Separate requested and actual flow control parameters
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch removes the TX and RX flow control flags from tg3_flags and
adds two new flow control variables, flowctrl and active_flowctrl.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 4942f7d..d503214 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1602,17 +1602,19 @@ static void tg3_link_report(struct tg3 *tp)
(tp->link_config.active_duplex == DUPLEX_FULL ?
"full" : "half"));
- printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
- "%s for RX.\n",
+ printk(KERN_INFO PFX
+ "%s: Flow control is %s for TX and %s for RX.\n",
tp->dev->name,
- (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off",
- (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off");
+ (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ?
+ "on" : "off",
+ (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ?
+ "on" : "off");
}
}
static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
{
- u32 new_tg3_flags = 0;
+ u8 new_tg3_flags = 0;
u32 old_rx_mode = tp->rx_mode;
u32 old_tx_mode = tp->tx_mode;
@@ -1639,31 +1641,27 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
if (local_adv & ADVERTISE_PAUSE_CAP) {
if (local_adv & ADVERTISE_PAUSE_ASYM) {
if (remote_adv & LPA_PAUSE_CAP)
- new_tg3_flags |=
- (TG3_FLAG_RX_PAUSE |
- TG3_FLAG_TX_PAUSE);
+ new_tg3_flags = TG3_FLOW_CTRL_RX |
+ TG3_FLOW_CTRL_TX;
else if (remote_adv & LPA_PAUSE_ASYM)
- new_tg3_flags |=
- (TG3_FLAG_RX_PAUSE);
+ new_tg3_flags = TG3_FLOW_CTRL_RX;
} else {
if (remote_adv & LPA_PAUSE_CAP)
- new_tg3_flags |=
- (TG3_FLAG_RX_PAUSE |
- TG3_FLAG_TX_PAUSE);
+ new_tg3_flags = TG3_FLOW_CTRL_RX |
+ TG3_FLOW_CTRL_TX;
}
} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
if ((remote_adv & LPA_PAUSE_CAP) &&
- (remote_adv & LPA_PAUSE_ASYM))
- new_tg3_flags |= TG3_FLAG_TX_PAUSE;
+ (remote_adv & LPA_PAUSE_ASYM))
+ new_tg3_flags = TG3_FLOW_CTRL_TX;
}
-
- tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
- tp->tg3_flags |= new_tg3_flags;
} else {
- new_tg3_flags = tp->tg3_flags;
+ new_tg3_flags = tp->link_config.flowctrl;
}
- if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
+ tp->link_config.active_flowctrl = new_tg3_flags;
+
+ if (new_tg3_flags & TG3_FLOW_CTRL_RX)
tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
else
tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
@@ -1672,7 +1670,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
- if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
+ if (new_tg3_flags & TG3_FLOW_CTRL_TX)
tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
else
tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
@@ -2812,9 +2810,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
int current_link_up;
int i;
- orig_pause_cfg =
- (tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
- TG3_FLAG_TX_PAUSE));
+ orig_pause_cfg = tp->link_config.active_flowctrl;
orig_active_speed = tp->link_config.active_speed;
orig_active_duplex = tp->link_config.active_duplex;
@@ -2903,9 +2899,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
netif_carrier_off(tp->dev);
tg3_link_report(tp);
} else {
- u32 now_pause_cfg =
- tp->tg3_flags & (TG3_FLAG_RX_PAUSE |
- TG3_FLAG_TX_PAUSE);
+ u32 now_pause_cfg = tp->link_config.active_flowctrl;
if (orig_pause_cfg != now_pause_cfg ||
orig_active_speed != tp->link_config.active_speed ||
orig_active_duplex != tp->link_config.active_duplex)
@@ -8571,8 +8565,16 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
struct tg3 *tp = netdev_priv(dev);
epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
- epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
- epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
+
+ if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX)
+ epause->rx_pause = 1;
+ else
+ epause->rx_pause = 0;
+
+ if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX)
+ epause->tx_pause = 1;
+ else
+ epause->tx_pause = 0;
}
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -8592,13 +8594,13 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
else
tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
if (epause->rx_pause)
- tp->tg3_flags |= TG3_FLAG_RX_PAUSE;
+ tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX;
else
- tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE;
+ tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX;
if (epause->tx_pause)
- tp->tg3_flags |= TG3_FLAG_TX_PAUSE;
+ tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX;
else
- tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
+ tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX;
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -12620,6 +12622,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
/* flow control autonegotiation is default behavior */
tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+ tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
tg3_init_coal(tp);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index da18fb2..ac47c17 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2103,13 +2103,18 @@ struct tg3_link_config {
u16 speed;
u8 duplex;
u8 autoneg;
+ u8 flowctrl;
+#define TG3_FLOW_CTRL_TX 0x01
+#define TG3_FLOW_CTRL_RX 0x02
/* Describes what we actually have. */
- u16 active_speed;
+ u8 active_flowctrl;
+
u8 active_duplex;
#define SPEED_INVALID 0xffff
#define DUPLEX_INVALID 0xff
#define AUTONEG_INVALID 0xff
+ u16 active_speed;
/* When we go in and out of low power mode we need
* to swap with this state.
@@ -2337,8 +2342,6 @@ struct tg3 {
#define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000
#define TG3_FLAG_NVRAM 0x00002000
#define TG3_FLAG_NVRAM_BUFFERED 0x00004000
-#define TG3_FLAG_RX_PAUSE 0x00008000
-#define TG3_FLAG_TX_PAUSE 0x00010000
#define TG3_FLAG_PCIX_MODE 0x00020000
#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000
#define TG3_FLAG_PCI_32BIT 0x00080000
^ permalink raw reply related
* [PATCH 2/8] tg3: Add 1000T & 1000X flowctrl resolvers
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch adds two new utility functions to resolve flow control. One
function resolves flow control based on 1000-BaseT register definitions.
The other resolves flow control based on 1000-Base X register
definitions.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index d503214..0cb0a6a 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1612,6 +1612,50 @@ static void tg3_link_report(struct tg3 *tp)
}
}
+static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
+{
+ u8 cap = 0;
+
+ if (lcladv & ADVERTISE_PAUSE_CAP) {
+ if (lcladv & ADVERTISE_PAUSE_ASYM) {
+ if (rmtadv & LPA_PAUSE_CAP)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ else if (rmtadv & LPA_PAUSE_ASYM)
+ cap = TG3_FLOW_CTRL_RX;
+ } else {
+ if (rmtadv & LPA_PAUSE_CAP)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ }
+ } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
+ if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
+ cap = TG3_FLOW_CTRL_TX;
+ }
+
+ return cap;
+}
+
+static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv)
+{
+ u8 cap = 0;
+
+ if (lcladv & ADVERTISE_1000XPAUSE) {
+ if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+ if (rmtadv & LPA_1000XPAUSE)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ else if (rmtadv & LPA_1000XPAUSE_ASYM)
+ cap = TG3_FLOW_CTRL_RX;
+ } else {
+ if (rmtadv & LPA_1000XPAUSE)
+ cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX;
+ }
+ } else if (lcladv & ADVERTISE_1000XPSE_ASYM) {
+ if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM))
+ cap = TG3_FLOW_CTRL_TX;
+ }
+
+ return cap;
+}
+
static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
{
u8 new_tg3_flags = 0;
@@ -1619,42 +1663,12 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
u32 old_tx_mode = tp->tx_mode;
if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
-
- /* Convert 1000BaseX flow control bits to 1000BaseT
- * bits before resolving flow control.
- */
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
- local_adv &= ~(ADVERTISE_PAUSE_CAP |
- ADVERTISE_PAUSE_ASYM);
- remote_adv &= ~(LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
- if (local_adv & ADVERTISE_1000XPAUSE)
- local_adv |= ADVERTISE_PAUSE_CAP;
- if (local_adv & ADVERTISE_1000XPSE_ASYM)
- local_adv |= ADVERTISE_PAUSE_ASYM;
- if (remote_adv & LPA_1000XPAUSE)
- remote_adv |= LPA_PAUSE_CAP;
- if (remote_adv & LPA_1000XPAUSE_ASYM)
- remote_adv |= LPA_PAUSE_ASYM;
- }
-
- if (local_adv & ADVERTISE_PAUSE_CAP) {
- if (local_adv & ADVERTISE_PAUSE_ASYM) {
- if (remote_adv & LPA_PAUSE_CAP)
- new_tg3_flags = TG3_FLOW_CTRL_RX |
- TG3_FLOW_CTRL_TX;
- else if (remote_adv & LPA_PAUSE_ASYM)
- new_tg3_flags = TG3_FLOW_CTRL_RX;
- } else {
- if (remote_adv & LPA_PAUSE_CAP)
- new_tg3_flags = TG3_FLOW_CTRL_RX |
- TG3_FLOW_CTRL_TX;
- }
- } else if (local_adv & ADVERTISE_PAUSE_ASYM) {
- if ((remote_adv & LPA_PAUSE_CAP) &&
- (remote_adv & LPA_PAUSE_ASYM))
- new_tg3_flags = TG3_FLOW_CTRL_TX;
- }
+ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
+ remote_adv);
+ else
+ new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv,
+ remote_adv);
} else {
new_tg3_flags = tp->link_config.flowctrl;
}
^ permalink raw reply related
* [PATCH 4/8] tg3: Replace some magic 5704S constants
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch replaces magic values with preprocessor definitions for
the sg_dig_ctrl and sg_dig_status registers. This is preparatory work
for the next patch.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 9e51457..9985166 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -2683,7 +2683,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
sg_dig_ctrl = tr32(SG_DIG_CTRL);
if (tp->link_config.autoneg != AUTONEG_ENABLE) {
- if (sg_dig_ctrl & (1 << 31)) {
+ if (sg_dig_ctrl & SG_DIG_USING_HW_AUTONEG) {
if (workaround) {
u32 val = serdes_cfg;
@@ -2693,7 +2693,8 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
- tw32_f(SG_DIG_CTRL, 0x01388400);
+
+ tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
}
if (mac_status & MAC_STATUS_PCS_SYNCED) {
tg3_setup_flow_control(tp, 0, 0);
@@ -2703,13 +2704,13 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
}
/* Want auto-negotiation. */
- expected_sg_dig_ctrl = 0x81388400;
+ expected_sg_dig_ctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_COMMON_SETUP;
/* Pause capability */
- expected_sg_dig_ctrl |= (1 << 11);
+ expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP;
/* Asymettric pause */
- expected_sg_dig_ctrl |= (1 << 12);
+ expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
@@ -2724,7 +2725,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
restart_autoneg:
if (workaround)
tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
- tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+ tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | SG_DIG_SOFT_RESET);
udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
@@ -2735,22 +2736,22 @@ restart_autoneg:
sg_dig_status = tr32(SG_DIG_STATUS);
mac_status = tr32(MAC_STATUS);
- if ((sg_dig_status & (1 << 1)) &&
+ if ((sg_dig_status & SG_DIG_AUTONEG_COMPLETE) &&
(mac_status & MAC_STATUS_PCS_SYNCED)) {
u32 local_adv, remote_adv;
local_adv = ADVERTISE_PAUSE_CAP;
remote_adv = 0;
- if (sg_dig_status & (1 << 19))
+ if (sg_dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
remote_adv |= LPA_PAUSE_CAP;
- if (sg_dig_status & (1 << 20))
+ if (sg_dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
remote_adv |= LPA_PAUSE_ASYM;
tg3_setup_flow_control(tp, local_adv, remote_adv);
current_link_up = 1;
tp->serdes_counter = 0;
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
- } else if (!(sg_dig_status & (1 << 1))) {
+ } else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) {
if (tp->serdes_counter)
tp->serdes_counter--;
else {
@@ -2765,7 +2766,7 @@ restart_autoneg:
tw32_f(MAC_SERDES_CFG, val);
}
- tw32_f(SG_DIG_CTRL, 0x01388400);
+ tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP);
udelay(40);
/* Link parallel detection - link is up */
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index ac47c17..3938eb3 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -545,6 +545,8 @@
#define SG_DIG_FIBER_MODE 0x00008000
#define SG_DIG_REMOTE_FAULT_MASK 0x00006000
#define SG_DIG_PAUSE_MASK 0x00001800
+#define SG_DIG_PAUSE_CAP 0x00000800
+#define SG_DIG_ASYM_PAUSE 0x00001000
#define SG_DIG_GBIC_ENABLE 0x00000400
#define SG_DIG_CHECK_END_ENABLE 0x00000200
#define SG_DIG_SGMII_AUTONEG_TIMER 0x00000100
@@ -556,6 +558,11 @@
#define SG_DIG_AUTONEG_LOW_ENABLE 0x00000004
#define SG_DIG_REMOTE_LOOPBACK 0x00000002
#define SG_DIG_LOOPBACK 0x00000001
+#define SG_DIG_COMMON_SETUP (SG_DIG_CRC16_CLEAR_N | \
+ SG_DIG_LOCAL_DUPLEX_STATUS | \
+ SG_DIG_LOCAL_LINK_STATUS | \
+ (0x2 << SG_DIG_SPEED_STATUS_SHIFT) | \
+ SG_DIG_FIBER_MODE | SG_DIG_GBIC_ENABLE)
#define SG_DIG_STATUS 0x000005b4
#define SG_DIG_CRC16_BUS_MASK 0xffff0000
#define SG_DIG_PARTNER_FAULT_MASK 0x00600000 /* If !MRADV_CRC16_SELECT */
^ permalink raw reply related
* [PATCH 3/8] tg3: Add 1000T & 1000X flowctl adv helpers
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch adds two functions designed to convert abstract TX & RX
flow control parameters to 1000-BaseT and 1000-BaseX autonegotiation
advertisements. Code that uses standard definitions which statically
advertises TX & RX flow control has been replaced with code that
configures the advertisements based on administrator dictated
preferences.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 0cb0a6a..9e51457 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1612,6 +1612,38 @@ static void tg3_link_report(struct tg3 *tp)
}
}
+static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl)
+{
+ u16 miireg;
+
+ if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+ miireg = ADVERTISE_PAUSE_CAP;
+ else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+ miireg = ADVERTISE_PAUSE_ASYM;
+ else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+ miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+ else
+ miireg = 0;
+
+ return miireg;
+}
+
+static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl)
+{
+ u16 miireg;
+
+ if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX))
+ miireg = ADVERTISE_1000XPAUSE;
+ else if (flow_ctrl & TG3_FLOW_CTRL_TX)
+ miireg = ADVERTISE_1000XPSE_ASYM;
+ else if (flow_ctrl & TG3_FLOW_CTRL_RX)
+ miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
+ else
+ miireg = 0;
+
+ return miireg;
+}
+
static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv)
{
u8 cap = 0;
@@ -1764,7 +1796,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
~(ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full);
- new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ new_adv = ADVERTISE_CSMA;
if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
new_adv |= ADVERTISE_10HALF;
if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
@@ -1773,6 +1805,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
new_adv |= ADVERTISE_100HALF;
if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
new_adv |= ADVERTISE_100FULL;
+
+ new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
tg3_writephy(tp, MII_ADVERTISE, new_adv);
if (tp->link_config.advertising &
@@ -1792,9 +1827,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_CTRL, 0);
}
} else {
+ new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+ new_adv |= ADVERTISE_CSMA;
+
/* Asking for a specific link mode. */
if (tp->link_config.speed == SPEED_1000) {
- new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
tg3_writephy(tp, MII_ADVERTISE, new_adv);
if (tp->link_config.duplex == DUPLEX_FULL)
@@ -1805,11 +1842,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
new_adv |= (MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER);
- tg3_writephy(tp, MII_TG3_CTRL, new_adv);
} else {
- tg3_writephy(tp, MII_TG3_CTRL, 0);
-
- new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
if (tp->link_config.speed == SPEED_100) {
if (tp->link_config.duplex == DUPLEX_FULL)
new_adv |= ADVERTISE_100FULL;
@@ -1822,7 +1855,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
new_adv |= ADVERTISE_10HALF;
}
tg3_writephy(tp, MII_ADVERTISE, new_adv);
+
+ new_adv = 0;
}
+
+ tg3_writephy(tp, MII_TG3_CTRL, new_adv);
}
if (tp->link_config.autoneg == AUTONEG_DISABLE &&
@@ -2118,17 +2155,15 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
local_adv = 0;
- local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
if (tg3_readphy(tp, MII_LPA, &remote_adv))
remote_adv = 0;
- remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
-
- /* If we are not advertising full pause capability,
- * something is wrong. Bring the link down and reconfigure.
+ /* If we are not advertising what has been requested,
+ * bring the link down and reconfigure.
*/
- if (local_adv != ADVERTISE_PAUSE_CAP) {
+ if (local_adv !=
+ tg3_advert_flowctrl_1000T(tp->link_config.flowctrl)) {
current_link_up = 0;
} else {
tg3_setup_flow_control(tp, local_adv, remote_adv);
@@ -2973,8 +3008,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
ADVERTISE_1000XPSE_ASYM |
ADVERTISE_SLCT);
- /* Always advertise symmetric PAUSE just like copper */
- new_adv |= ADVERTISE_1000XPAUSE;
+ new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
new_adv |= ADVERTISE_1000XHALF;
^ permalink raw reply related
* [PATCH 7/8] tg3: Fix supporting flowctrl code
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch does three things. It modifies tg3_setup_flow_control() to
use the administrator requested flow control settings if
autonegotiation is turned off. It slightly modifies the
tg3_setup_fiber_mii_phy() function to account for this new use case.
And finally, it does the same for tg3_setup_copper_phy().
The copper modifications are more than a small multi-line change. The
new code makes an attempt to avoid a link renegotiation if the link is
active at half duplex and the only difference between the current
advertised settings and requested advertised settings is the
flow control advertisements.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 373642c..dd9229c 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1694,7 +1694,8 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
u32 old_rx_mode = tp->rx_mode;
u32 old_tx_mode = tp->tx_mode;
- if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
+ if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+ (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
remote_adv);
@@ -1975,10 +1976,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask)
return 1;
}
+static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
+{
+ u32 curadv, reqadv;
+
+ if (tg3_readphy(tp, MII_ADVERTISE, lcladv))
+ return 1;
+
+ curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+ reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
+
+ if (tp->link_config.active_duplex == DUPLEX_FULL) {
+ if (curadv != reqadv)
+ return 0;
+
+ if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)
+ tg3_readphy(tp, MII_LPA, rmtadv);
+ } else {
+ /* Reprogram the advertisement register, even if it
+ * does not affect the current link. If the link
+ * gets renegotiated in the future, we can save an
+ * additional renegotiation cycle by advertising
+ * it correctly in the first place.
+ */
+ if (curadv != reqadv) {
+ *lcladv &= ~(ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv);
+ }
+ }
+
+ return 1;
+}
+
static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
{
int current_link_up;
u32 bmsr, dummy;
+ u32 lcl_adv, rmt_adv;
u16 current_speed;
u8 current_duplex;
int i, err;
@@ -2121,54 +2156,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
udelay(10);
}
- if (tp->link_config.autoneg == AUTONEG_ENABLE) {
- if (bmcr & BMCR_ANENABLE) {
- current_link_up = 1;
+ lcl_adv = 0;
+ rmt_adv = 0;
- /* Force autoneg restart if we are exiting
- * low power mode.
- */
- if (!tg3_copper_is_advertising_all(tp,
- tp->link_config.advertising))
- current_link_up = 0;
- } else {
- current_link_up = 0;
+ tp->link_config.active_speed = current_speed;
+ tp->link_config.active_duplex = current_duplex;
+
+ if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ if ((bmcr & BMCR_ANENABLE) &&
+ tg3_copper_is_advertising_all(tp,
+ tp->link_config.advertising)) {
+ if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv,
+ &rmt_adv))
+ current_link_up = 1;
}
} else {
if (!(bmcr & BMCR_ANENABLE) &&
tp->link_config.speed == current_speed &&
- tp->link_config.duplex == current_duplex) {
+ tp->link_config.duplex == current_duplex &&
+ tp->link_config.flowctrl ==
+ tp->link_config.active_flowctrl) {
current_link_up = 1;
- } else {
- current_link_up = 0;
}
}
- tp->link_config.active_speed = current_speed;
- tp->link_config.active_duplex = current_duplex;
+ if (current_link_up == 1 &&
+ tp->link_config.active_duplex == DUPLEX_FULL)
+ tg3_setup_flow_control(tp, lcl_adv, rmt_adv);
}
- if (current_link_up == 1 &&
- (tp->link_config.active_duplex == DUPLEX_FULL) &&
- (tp->link_config.autoneg == AUTONEG_ENABLE)) {
- u32 local_adv, remote_adv;
-
- if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
- local_adv = 0;
-
- if (tg3_readphy(tp, MII_LPA, &remote_adv))
- remote_adv = 0;
-
- /* If we are not advertising what has been requested,
- * bring the link down and reconfigure.
- */
- if (local_adv !=
- tg3_advert_flowctrl_1000T(tp->link_config.flowctrl)) {
- current_link_up = 0;
- } else {
- tg3_setup_flow_control(tp, local_adv, remote_adv);
- }
- }
relink:
if (current_link_up == 0 || tp->link_config.phy_is_low_power) {
u32 tmp;
@@ -2981,6 +2997,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
u32 bmsr, bmcr;
u16 current_speed;
u8 current_duplex;
+ u32 local_adv, remote_adv;
tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32_f(MAC_MODE, tp->mac_mode);
@@ -3014,7 +3031,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
err |= tg3_readphy(tp, MII_BMCR, &bmcr);
if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset &&
- (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+ (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+ tp->link_config.flowctrl == tp->link_config.active_flowctrl) {
/* do nothing, just check for link up at the end */
} else if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 adv, new_adv;
@@ -3096,8 +3114,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
else
current_duplex = DUPLEX_HALF;
+ local_adv = 0;
+ remote_adv = 0;
+
if (bmcr & BMCR_ANENABLE) {
- u32 local_adv, remote_adv, common;
+ u32 common;
err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv);
err |= tg3_readphy(tp, MII_LPA, &remote_adv);
@@ -3108,15 +3129,15 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
current_duplex = DUPLEX_FULL;
else
current_duplex = DUPLEX_HALF;
-
- tg3_setup_flow_control(tp, local_adv,
- remote_adv);
}
else
current_link_up = 0;
}
}
+ if (current_link_up == 1 && current_duplex == DUPLEX_FULL)
+ tg3_setup_flow_control(tp, local_adv, remote_adv);
+
tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
if (tp->link_config.active_duplex == DUPLEX_HALF)
tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
^ permalink raw reply related
* [PATCH 5/8] tg3: Correct 5704S flowctrl advertisements
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch modifies the 5704S hardware autoneg code to use the
administrator specified flow control parameters. Since the 5704S uses
device specific flow control enumerations, the 1000-BaseX utility
functions are used and code was added to convert the definitions to and
from the proprietary enumerations.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 9985166..e30a99f 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1695,7 +1695,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
u32 old_tx_mode = tp->tx_mode;
if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
- if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ if (tp->tg3_flags2 & (TG3_FLG2_MII_SERDES|TG3_FLG2_HW_AUTONEG))
new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
remote_adv);
else
@@ -2658,6 +2658,7 @@ static void tg3_init_bcm8002(struct tg3 *tp)
static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
{
+ u16 flowctrl;
u32 sg_dig_ctrl, sg_dig_status;
u32 serdes_cfg, expected_sg_dig_ctrl;
int workaround, port_a;
@@ -2706,11 +2707,11 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
/* Want auto-negotiation. */
expected_sg_dig_ctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_COMMON_SETUP;
- /* Pause capability */
- expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP;
-
- /* Asymettric pause */
- expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
+ flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+ if (flowctrl & ADVERTISE_1000XPAUSE)
+ expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP;
+ if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+ expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE;
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
@@ -2738,14 +2739,17 @@ restart_autoneg:
if ((sg_dig_status & SG_DIG_AUTONEG_COMPLETE) &&
(mac_status & MAC_STATUS_PCS_SYNCED)) {
- u32 local_adv, remote_adv;
+ u32 local_adv = 0, remote_adv = 0;
+
+ if (sg_dig_ctrl & SG_DIG_PAUSE_CAP)
+ local_adv |= ADVERTISE_1000XPAUSE;
+ if (sg_dig_ctrl & SG_DIG_ASYM_PAUSE)
+ local_adv |= ADVERTISE_1000XPSE_ASYM;
- local_adv = ADVERTISE_PAUSE_CAP;
- remote_adv = 0;
if (sg_dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE)
- remote_adv |= LPA_PAUSE_CAP;
+ remote_adv |= LPA_1000XPAUSE;
if (sg_dig_status & SG_DIG_PARTNER_ASYM_PAUSE)
- remote_adv |= LPA_PAUSE_ASYM;
+ remote_adv |= LPA_1000XPAUSE_ASYM;
tg3_setup_flow_control(tp, local_adv, remote_adv);
current_link_up = 1;
^ permalink raw reply related
* [PATCH 6/8] tg3: Correct sw autoneg flow control advertisements
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch modifies the software autoneg code to use the administrator
specified flow control parameters. Since the autonegotiation code uses
alternative flow control enumerations, the 1000-BaseX utility functions
are used and code was added to convert the definitions to and from the
alternate enumerations.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e30a99f..373642c 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -1695,7 +1695,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
u32 old_tx_mode = tp->tx_mode;
if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
- if (tp->tg3_flags2 & (TG3_FLG2_MII_SERDES|TG3_FLG2_HW_AUTONEG))
+ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES)
new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv,
remote_adv);
else
@@ -2317,6 +2317,7 @@ struct tg3_fiber_aneginfo {
static int tg3_fiber_aneg_smachine(struct tg3 *tp,
struct tg3_fiber_aneginfo *ap)
{
+ u16 flowctrl;
unsigned long delta;
u32 rx_cfg_reg;
int ret;
@@ -2416,7 +2417,12 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
case ANEG_STATE_ABILITY_DETECT_INIT:
ap->flags &= ~(MR_TOGGLE_TX);
- ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
+ ap->txconfig = ANEG_CFG_FD;
+ flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl);
+ if (flowctrl & ADVERTISE_1000XPAUSE)
+ ap->txconfig |= ANEG_CFG_PS1;
+ if (flowctrl & ADVERTISE_1000XPSE_ASYM)
+ ap->txconfig |= ANEG_CFG_PS2;
tw32(MAC_TX_AUTO_NEG, ap->txconfig);
tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
tw32_f(MAC_MODE, tp->mac_mode);
@@ -2562,7 +2568,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
return ret;
}
-static int fiber_autoneg(struct tg3 *tp, u32 *flags)
+static int fiber_autoneg(struct tg3 *tp, u32 *txflags, u32 *rxflags)
{
int res = 0;
struct tg3_fiber_aneginfo aninfo;
@@ -2596,7 +2602,8 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags)
tw32_f(MAC_MODE, tp->mac_mode);
udelay(40);
- *flags = aninfo.flags;
+ *txflags = aninfo.txconfig;
+ *rxflags = aninfo.flags;
if (status == ANEG_DONE &&
(aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK |
@@ -2806,18 +2813,21 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
goto out;
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
- u32 flags;
+ u32 txflags, rxflags;
int i;
- if (fiber_autoneg(tp, &flags)) {
- u32 local_adv, remote_adv;
+ if (fiber_autoneg(tp, &txflags, &rxflags)) {
+ u32 local_adv = 0, remote_adv = 0;
- local_adv = ADVERTISE_PAUSE_CAP;
- remote_adv = 0;
- if (flags & MR_LP_ADV_SYM_PAUSE)
- remote_adv |= LPA_PAUSE_CAP;
- if (flags & MR_LP_ADV_ASYM_PAUSE)
- remote_adv |= LPA_PAUSE_ASYM;
+ if (txflags & ANEG_CFG_PS1)
+ local_adv |= ADVERTISE_1000XPAUSE;
+ if (txflags & ANEG_CFG_PS2)
+ local_adv |= ADVERTISE_1000XPSE_ASYM;
+
+ if (rxflags & MR_LP_ADV_SYM_PAUSE)
+ remote_adv |= LPA_1000XPAUSE;
+ if (rxflags & MR_LP_ADV_ASYM_PAUSE)
+ remote_adv |= LPA_1000XPAUSE_ASYM;
tg3_setup_flow_control(tp, local_adv, remote_adv);
@@ -2841,6 +2851,8 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
!(mac_status & MAC_STATUS_RCVD_CFG))
current_link_up = 1;
} else {
+ tg3_setup_flow_control(tp, 0, 0);
+
/* Forcing 1000FD link up. */
current_link_up = 1;
^ permalink raw reply related
* [PATCH 8/8] tg3: Update version to 3.87
From: Matt Carlson @ 2007-12-20 23:21 UTC (permalink / raw)
To: davem; +Cc: netdev, Michael Chan, andy
This patch updates the version number to 3.87.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index dd9229c..6264454 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.86"
-#define DRV_MODULE_RELDATE "November 9, 2007"
+#define DRV_MODULE_VERSION "3.87"
+#define DRV_MODULE_RELDATE "December 20, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
^ permalink raw reply related
* Re: Update ip command line processing
From: David Miller @ 2007-12-20 23:21 UTC (permalink / raw)
To: horms; +Cc: linux-kernel, netdev, apw
In-Reply-To: <20071218085730.GA10765@verge.net.au>
From: Simon Horman <horms@verge.net.au>
Date: Tue, 18 Dec 2007 17:57:32 +0900
> @@ -1414,9 +1414,16 @@ late_initcall(ip_auto_config);
> */
> static int __init ic_proto_name(char *name)
> {
> + if (!name) {
> + return 1;
> + }
I do not see any circumstance under which this pointer can
be NULL. Judging by your other changes, I think you mean
to use "!*name" here.
Maybe:
if (*name == '\0')
would make it clearer what you're checking for, an
empty string.
Otherwise I'm fine with your change.
^ permalink raw reply
* Re: [PATCH] drivers/net/niu: Support for Marvell PHY
From: David Miller @ 2007-12-20 23:25 UTC (permalink / raw)
To: mlindner; +Cc: netdev
In-Reply-To: <1197993838.26679.64.camel@mlindner-lin.skd.de>
From: Mirko Lindner <mlindner@marvell.com>
Date: Tue, 18 Dec 2007 17:03:58 +0100
> +static int xcvr_init_10g_mrvl88x2011(struct niu *np)
> +{
> + int err;
> +
> + /* Set LED functions */
> + mrvl88x2011_led_blink_rate(np, 2);
> + mrvl88x2011_act_led(np, 0); /* led activity */
> +
> + err = mdio_read(np, np->phy_addr, 3, 0x8300);
> + if (err < 0) {
> + return(err);
> + }
> +
> + err |= 0x0001;
> +
> + err = mdio_write(np, np->phy_addr, 3, 0x8300, err);
> + if (err < 0) {
> + return(err);
> + }
> +
> + /* Enable PMD */
> + err = mdio_write(np, np->phy_addr, 1, 0x0009, 0);
> +
> + return (err);
> +}
> +
This code doesn't handle putting the PHY into loopback more etc. like
the BCM8704 chip initialization does.
Please also fully document the registers using defines in the niu.h
header file as is already done for the BCM8704 registers. Magic
constants are not allowed.
I'd like this Marvell PHY chip to be documented so that, just like the
BCM8704, someone can look at the driver and understand how the chip
works and thus make bug fixes and changes.
^ permalink raw reply
* Re: [PATCH 2/2] net: neighbor timer power saving
From: David Miller @ 2007-12-20 23:28 UTC (permalink / raw)
To: dada1; +Cc: shemminger, parag.warudkar, netdev, akpm
In-Reply-To: <4768C6FF.2090909@cosmosbay.com>
From: Eric Dumazet <dada1@cosmosbay.com>
Date: Wed, 19 Dec 2007 08:23:43 +0100
> We are going to convert 99% timers to deferrable.
>
> Maybe the right move should be to have the reverse attribute, to
> mark a timer as non deferrable...
I think we are still in a learning process about what
exactly causes a timer to be converted to deferrable
or not.
It may sound crazy but flipping the switch on %99 of
our kernel timers is not the nicest way to figure it
out :-)
Therefore it might still make sense to keep the deferrable
marker for now, so that we can gradually convert the tree
checking easy case carefully. This way the breakage is
containted very well.
Then once we have almost all of the timers verified, we
can reverse the meaning and mark the timers that remain
as non-deferrable and kill the deferrable marker.
^ permalink raw reply
* Re: [PATCH net-2.6.25 (resend) 1/3] Uninline the __inet_hash function
From: David Miller @ 2007-12-20 23:31 UTC (permalink / raw)
To: xemul; +Cc: dada1, netdev, devel
In-Reply-To: <476A39DF.5080604@openvz.org>
From: Pavel Emelyanov <xemul@openvz.org>
Date: Thu, 20 Dec 2007 12:46:07 +0300
> This one is used in quite many places in the networking code and
> seems to big to be inline.
>
> After the patch net/ipv4/build-in.o loses ~650 bytes:
> add/remove: 2/0 grow/shrink: 0/5 up/down: 461/-1114 (-653)
> function old new delta
> __inet_hash_nolisten - 282 +282
> __inet_hash - 179 +179
> tcp_sacktag_write_queue 2255 2254 -1
> __inet_lookup_listener 284 274 -10
> tcp_v4_syn_recv_sock 755 493 -262
> tcp_v4_hash 389 35 -354
> inet_hash_connect 1086 599 -487
>
> This version addresses the issue pointed by Eric, that
> while being inline this function was optimized by gcc
> in respect to the 'listen_possible' argument.
>
> (Patches 2 and 3 in this series are still applied after this)
>
> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Applied.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox