net/sfc/base: import MCDI proxy authorization
authorAndrew Rybchenko <arybchenko@solarflare.com>
Tue, 29 Nov 2016 16:18:40 +0000 (16:18 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 17 Jan 2017 18:39:25 +0000 (19:39 +0100)
MCDI proxy authorization may be used if privileged PCI
function (physical function) would like to intercept and
authorize MCDI requests done by unprivileged (e.g. virtual)
PCI function. It may be used to control unprivileged
function Rx mode (e.g. promiscuous, all-multicast), MTU
and default MAC address change requests etc.

Current libefx support is limited to client-side which
is required to work when function requests need to be
authorized.

Server side support required to request and do the
authorization is not implemented yet.

EFSYS_OPT_MCDI_PROXY_AUTH should be enabled to use it.

From Solarflare Communications Inc.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
drivers/net/sfc/base/efx.h
drivers/net/sfc/base/efx_check.h
drivers/net/sfc/base/efx_mcdi.c
drivers/net/sfc/base/efx_mcdi.h

index 9fdfb96..d68a36b 100644 (file)
@@ -209,6 +209,9 @@ typedef struct efx_mcdi_transport_s {
        void            (*emt_logger)(void *, efx_log_msg_t,
                                        void *, size_t, void *, size_t);
 #endif /* EFSYS_OPT_MCDI_LOGGING */
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+       void            (*emt_ev_proxy_response)(void *, uint32_t, efx_rc_t);
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
 } efx_mcdi_transport_t;
 
 extern __checkReturn   efx_rc_t
index 228b42c..470f73c 100644 (file)
 # endif
 #endif /* EFSYS_OPT_MCDI_LOGGING */
 
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+/* Support MCDI proxy authorization */
+# if !EFSYS_OPT_MCDI
+#  error "MCDI_PROXY_AUTH requires MCDI"
+# endif
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
+
 #ifdef EFSYS_OPT_MON_LM87
 # error "MON_LM87 is obsolete and is not supported."
 #endif
index a87a223..474c505 100644 (file)
@@ -352,6 +352,21 @@ efx_mcdi_read_response_header(
                emrp->emr_err_code = err_code;
                emrp->emr_err_arg = err_arg;
 
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+               if ((err_code == MC_CMD_ERR_PROXY_PENDING) &&
+                   (err_len == sizeof (err))) {
+                       /*
+                        * The MCDI request would normally fail with EPERM, but
+                        * firmware has forwarded it to an authorization agent
+                        * attached to a privileged PF.
+                        *
+                        * Save the authorization request handle. The client
+                        * must wait for a PROXY_RESPONSE event, or timeout.
+                        */
+                       emrp->emr_proxy_handle = err_arg;
+               }
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
+
 #if EFSYS_OPT_MCDI_LOGGING
                if (emtp->emt_logger != NULL) {
                        emtp->emt_logger(emtp->emt_context,
@@ -372,6 +387,9 @@ efx_mcdi_read_response_header(
 
        emrp->emr_rc = 0;
        emrp->emr_out_length_used = data_len;
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+       emrp->emr_proxy_handle = 0;
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
        return;
 
 fail3:
@@ -732,6 +750,62 @@ efx_mcdi_ev_cpl(
        emtp->emt_ev_cpl(emtp->emt_context);
 }
 
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+
+       __checkReturn   efx_rc_t
+efx_mcdi_get_proxy_handle(
+       __in            efx_nic_t *enp,
+       __in            efx_mcdi_req_t *emrp,
+       __out           uint32_t *handlep)
+{
+       efx_rc_t rc;
+
+       /*
+        * Return proxy handle from MCDI request that returned with error
+        * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching
+        * PROXY_RESPONSE event.
+        */
+       if ((emrp == NULL) || (handlep == NULL)) {
+               rc = EINVAL;
+               goto fail1;
+       }
+       if ((emrp->emr_rc != 0) &&
+           (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) {
+               *handlep = emrp->emr_proxy_handle;
+               rc = 0;
+       } else {
+               *handlep = 0;
+               rc = ENOENT;
+       }
+       return (rc);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+       return (rc);
+}
+
+                       void
+efx_mcdi_ev_proxy_response(
+       __in            efx_nic_t *enp,
+       __in            unsigned int handle,
+       __in            unsigned int status)
+{
+       const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
+       efx_rc_t rc;
+
+       /*
+        * Handle results of an authorization request for a privileged MCDI
+        * command. If authorization was granted then we must re-issue the
+        * original MCDI request. If authorization failed or timed out,
+        * then the original MCDI request should be completed with the
+        * result code from this event.
+        */
+       rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status);
+
+       emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc);
+}
+#endif /* EFSYS_OPT_MCDI_PROXY_AUTH */
+
                        void
 efx_mcdi_ev_death(
        __in            efx_nic_t *enp,
index a408b5b..a62e921 100644 (file)
@@ -59,6 +59,9 @@ struct efx_mcdi_req_s {
        /* Internals: low level transport details */
        unsigned int    emr_err_code;
        unsigned int    emr_err_arg;
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+       uint32_t        emr_proxy_handle;
+#endif
 };
 
 typedef struct efx_mcdi_iface_s {
@@ -90,6 +93,20 @@ efx_mcdi_ev_cpl(
        __in            unsigned int outlen,
        __in            int errcode);
 
+#if EFSYS_OPT_MCDI_PROXY_AUTH
+extern __checkReturn   efx_rc_t
+efx_mcdi_get_proxy_handle(
+       __in            efx_nic_t *enp,
+       __in            efx_mcdi_req_t *emrp,
+       __out           uint32_t *handlep);
+
+extern                 void
+efx_mcdi_ev_proxy_response(
+       __in            efx_nic_t *enp,
+       __in            unsigned int handle,
+       __in            unsigned int status);
+#endif
+
 extern                 void
 efx_mcdi_ev_death(
        __in            efx_nic_t *enp,