connection_dispatch_operation(Connection *conn, Operation *op, Slapi_PBlock *pb)
{
    int32_t minssf = conn->c_minssf;
    int32_t minssf_exclude_rootdse = conn->c_minssf_exclude_rootdse;
#ifdef TCP_CORK
    int32_t enable_nagle = conn->c_enable_nagle;
    int32_t pop_cork = 0;
#endif

    /* Set the connid and op_id to be used by internal op logging */
    slapi_td_reset_internal_logging(conn->c_connid, op->o_opid);

    /* Get the effective key length now since the first SSL handshake should be complete */
    connection_set_ssl_ssf(conn);

    /* Copy the Connection DN and SSF into the operation struct */
    op_copy_identity(conn, op);

    if (slapi_operation_is_flag_set(op, OP_FLAG_REPLICATED)) {
        /* If it is replicated op, ignore the maxbersize. */
        ber_len_t maxbersize = 0;
        ber_sockbuf_ctrl(conn->c_sb, LBER_SB_OPT_SET_MAX_INCOMING, &maxbersize);
    }

    /* If the minimum SSF requirements are not met, only allow
     * bind and extended operations through.  The bind and extop
     * code will ensure that only SASL binds and startTLS are
     * allowed, which gives the connection a chance to meet the
     * SSF requirements.  We also allow UNBIND and ABANDON.*/
    /*
     * If nsslapd-minssf-exclude-rootdse is on, we have to go to the
     * next step and check if the operation is against rootdse or not.
     * Once found it's not on rootdse, return LDAP_UNWILLING_TO_PERFORM there.
     */
    if (!minssf_exclude_rootdse &&
        (conn->c_sasl_ssf < minssf) && (conn->c_ssl_ssf < minssf) &&
        (conn->c_local_ssf < minssf) && (op->o_tag != LDAP_REQ_BIND) &&
        (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) &&
        (op->o_tag != LDAP_REQ_ABANDON)) {
        slapi_log_access(LDAP_DEBUG_STATS,
                         "conn=%" PRIu64 " op=%d UNPROCESSED OPERATION"
                         " - Insufficient SSF (local_ssf=%d sasl_ssf=%d ssl_ssf=%d)\n",
                         conn->c_connid, op->o_opid, conn->c_local_ssf,
                         conn->c_sasl_ssf, conn->c_ssl_ssf);
        send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
                         "Minimum SSF not met.", 0, NULL);
        return;
    }

    /* If anonymous access is disabled and the connection is
     * not authenticated, only allow bind and extended operations.
     * We allow extended operations so one can do a startTLS prior
     * to binding to protect their credentials in transit.
     * We also allow UNBIND and ABANDON.
     *
     * If anonymous access is only allowed for root DSE searches,
     * we let SEARCH operations through as well.  The search code
     * is responsible for checking if the operation is a root DSE
     * search. */
    if ((slapi_sdn_get_dn(&(op->o_sdn)) == NULL) &&
        /* anon access off and something other than BIND, EXTOP, UNBIND or ABANDON */
        (((conn->c_anon_access == SLAPD_ANON_ACCESS_OFF) && (op->o_tag != LDAP_REQ_BIND) &&
          (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) && (op->o_tag != LDAP_REQ_ABANDON)) ||
         /* root DSE access only and something other than BIND, EXTOP, UNBIND, ABANDON, or SEARCH */
         ((conn->c_anon_access == SLAPD_ANON_ACCESS_ROOTDSE) && (op->o_tag != LDAP_REQ_BIND) &&
          (op->o_tag != LDAP_REQ_EXTENDED) && (op->o_tag != LDAP_REQ_UNBIND) &&
          (op->o_tag != LDAP_REQ_ABANDON) && (op->o_tag != LDAP_REQ_SEARCH)))) {
        slapi_log_access(LDAP_DEBUG_STATS,
                         "conn=%" PRIu64 " op=%d UNPROCESSED OPERATION"
                         " - Anonymous access not allowed\n",
                         conn->c_connid, op->o_opid);

        send_ldap_result(pb, LDAP_INAPPROPRIATE_AUTH, NULL,
                         "Anonymous access is not allowed.",
                         0, NULL);
        return;
    }

    /* process the operation */
    switch (op->o_tag) {
    case LDAP_REQ_BIND:
        operation_set_type(op, SLAPI_OPERATION_BIND);
        do_bind(pb);
        break;

    case LDAP_REQ_UNBIND:
        operation_set_type(op, SLAPI_OPERATION_UNBIND);
        do_unbind(pb);
        break;

    case LDAP_REQ_ADD:
        operation_set_type(op, SLAPI_OPERATION_ADD);
        do_add(pb);
        break;

    case LDAP_REQ_DELETE:
        operation_set_type(op, SLAPI_OPERATION_DELETE);
        do_delete(pb);
        break;

    case LDAP_REQ_MODRDN:
        operation_set_type(op, SLAPI_OPERATION_MODRDN);
        do_modrdn(pb);
        break;

    case LDAP_REQ_MODIFY:
        operation_set_type(op, SLAPI_OPERATION_MODIFY);
        do_modify(pb);
        break;

    case LDAP_REQ_COMPARE:
        operation_set_type(op, SLAPI_OPERATION_COMPARE);
        do_compare(pb);
        break;

    case LDAP_REQ_SEARCH:
        operation_set_type(op, SLAPI_OPERATION_SEARCH);

/* On Linux we can use TCP_CORK to get us 5-10% speed benefit when one entry is returned */
/* Nagle needs to be turned _on_, the default is _on_ on linux, in daemon.c */
#ifdef TCP_CORK
        if (enable_nagle && !conn->c_unix_local) {
            int i = 1;
            int ret = setsockopt(conn->c_sd, IPPROTO_TCP, TCP_CORK, &i, sizeof(i));
            if (ret < 0) {
                slapi_log_err(SLAPI_LOG_ERR, "connection_dispatch_operation",
                              "Failed to set TCP_CORK on connection %" PRIu64 "\n", conn->c_connid);
            }
            pop_cork = 1;
        }
#endif
        do_search(pb);

#ifdef TCP_CORK
        if (pop_cork) {
            /* Clear TCP_CORK to flush any unsent data but only if not LDAPI*/
            int i = 0;
            int ret = setsockopt(conn->c_sd, IPPROTO_TCP, TCP_CORK, &i, sizeof(i));
            if (ret < 0) {
                slapi_log_err(SLAPI_LOG_ERR, "connection_dispatch_operation",
                              "Failed to clear TCP_CORK on connection %" PRIu64 "\n", conn->c_connid);
            }
        }
#endif

        break;

    /* for some strange reason, the console is using this old obsolete
     * value for ABANDON so we have to support it until the console
     * get fixed
     * otherwise the console has VERY BAD performances when a fair amount
     * of entries are created in the DIT
     */
    case LDAP_REQ_ABANDON_30:
    case LDAP_REQ_ABANDON:
        operation_set_type(op, SLAPI_OPERATION_ABANDON);
        do_abandon(pb);
        break;

    case LDAP_REQ_EXTENDED:
        operation_set_type(op, SLAPI_OPERATION_EXTENDED);
        do_extended(pb);
        break;

    default:
        slapi_log_err(SLAPI_LOG_ERR,
                      "connection_dispatch_operation", "Ignoring unknown LDAP request (conn=%" PRIu64 ", tag=0x%lx)\n",
                      conn->c_connid, op->o_tag);
        break;
    }
}