static enum_func_status
php_mysqlnd_read_row_ex(MYSQLND_CONN_DATA * conn, MYSQLND_MEMORY_POOL * result_set_memory_pool,
						MYSQLND_MEMORY_POOL_CHUNK ** buffer,
						size_t * data_size, zend_bool persistent_alloc,
						unsigned int prealloc_more_bytes TSRMLS_DC)
{
	enum_func_status ret = PASS;
	MYSQLND_PACKET_HEADER header;
	zend_uchar * p = NULL;
	zend_bool first_iteration = TRUE;

	DBG_ENTER("php_mysqlnd_read_row_ex");

	/*
	  To ease the process the server splits everything in packets up to 2^24 - 1.
	  Even in the case the payload is evenly divisible by this value, the last
	  packet will be empty, namely 0 bytes. Thus, we can read every packet and ask
	  for next one if they have 2^24 - 1 sizes. But just read the header of a
	  zero-length byte, don't read the body, there is no such.
	*/

	*data_size = prealloc_more_bytes;
	while (1) {
		if (FAIL == mysqlnd_read_header(conn->net, &header, conn->stats, conn->error_info TSRMLS_CC)) {
			ret = FAIL;
			break;
		}

		*data_size += header.size;

		if (first_iteration) {
			first_iteration = FALSE;
			/*
			  We need a trailing \0 for the last string, in case of text-mode,
			  to be able to implement read-only variables. Thus, we add + 1.
			*/
			*buffer = result_set_memory_pool->get_chunk(result_set_memory_pool, *data_size + 1 TSRMLS_CC);
			if (!*buffer) {
				ret = FAIL;
				break;
			}
			p = (*buffer)->ptr;
		} else if (!first_iteration) {
			/* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
			if (!header.size) {
				break;
			}

			/*
			  We have to realloc the buffer.

			  We need a trailing \0 for the last string, in case of text-mode,
			  to be able to implement read-only variables.
			*/
			if (FAIL == (*buffer)->resize_chunk((*buffer), *data_size + 1 TSRMLS_CC)) {
				SET_OOM_ERROR(*conn->error_info);
				ret = FAIL;
				break;
			}
			/* The position could have changed, recalculate */
			p = (*buffer)->ptr + (*data_size - header.size);
		}

		if (PASS != (ret = conn->net->data->m.receive_ex(conn->net, p, header.size, conn->stats, conn->error_info TSRMLS_CC))) {
			DBG_ERR("Empty row packet body");
			php_error(E_WARNING, "Empty row packet body");
			break;
		}

		if (header.size < MYSQLND_MAX_PACKET_SIZE) {
			break;
		}
	}
	if (ret == FAIL && *buffer) {
		(*buffer)->free_chunk((*buffer) TSRMLS_CC);
		*buffer = NULL;
	}
	*data_size -= prealloc_more_bytes;
	DBG_RETURN(ret);


static void
php_mysqlnd_chg_user_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
{
	MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;

	if (p->new_auth_protocol) {
		mnd_efree(p->new_auth_protocol);
		p->new_auth_protocol = NULL;
	}
	p->new_auth_protocol_len = 0;

	if (p->new_auth_protocol_data) {
		mnd_efree(p->new_auth_protocol_data);
		p->new_auth_protocol_data = NULL;
	}
	p->new_auth_protocol_data_len = 0;

	if (!stack_allocation) {
		mnd_pefree(p, p->header.persistent);
	}


static
void php_mysqlnd_greet_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
{
	MYSQLND_PACKET_GREET *p= (MYSQLND_PACKET_GREET *) _packet;
	if (p->server_version) {
		efree(p->server_version);
		p->server_version = NULL;
	}
	if (p->auth_plugin_data && p->auth_plugin_data != p->intern_auth_plugin_data) {
		efree(p->auth_plugin_data);
		p->auth_plugin_data = NULL;
	}
	if (p->auth_protocol) {
		efree(p->auth_protocol);
		p->auth_protocol = NULL;
	}
	if (!stack_allocation) {
		mnd_pefree(p, p->header.persistent);
	}


static struct st_mysqlnd_packet_auth *
MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
{
	struct st_mysqlnd_packet_auth * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_PACKET].struct_size, persistent);
	DBG_ENTER("mysqlnd_protocol::get_auth_packet");
	if (packet) {
		packet->header.m = &packet_methods[PROT_AUTH_PACKET];
		packet->header.persistent = persistent;
	}
	DBG_RETURN(packet);


zend_uchar *
php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length)
{
	if (length < (uint64_t) L64(251)) {
		*packet = (zend_uchar) length;
		return packet + 1;
	}

	if (length < (uint64_t) L64(65536)) {
		*packet++ = 252;
		int2store(packet,(unsigned int) length);
		return packet + 2;
	}

	if (length < (uint64_t) L64(16777216)) {
		*packet++ = 253;
		int3store(packet,(ulong) length);
		return packet + 3;
	}
	*packet++ = 254;
	int8store(packet, length);
	return packet + 8;


static void
php_mysqlnd_prepare_free_mem(void * _packet, zend_bool stack_allocation TSRMLS_DC)
{
	MYSQLND_PACKET_PREPARE_RESPONSE *p= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet;
	if (!stack_allocation) {
		mnd_pefree(p, p->header.persistent);
	}


static enum_func_status
php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
								char *error, int error_buf_len,
								unsigned int *error_no, char *sqlstate TSRMLS_DC)
{
	zend_uchar *p = buf;
	int error_msg_len= 0;

	DBG_ENTER("php_mysqlnd_read_error_from_line");

	*error_no = CR_UNKNOWN_ERROR;
	memcpy(sqlstate, unknown_sqlstate, MYSQLND_SQLSTATE_LENGTH);

	if (buf_len > 2) {
		*error_no = uint2korr(p);
		p+= 2;
		/*
		  sqlstate is following. No need to check for buf_left_len as we checked > 2 above,
		  if it was >=2 then we would need a check
		*/
		if (*p == '#') {
			++p;
			if ((buf_len - (p - buf)) >= MYSQLND_SQLSTATE_LENGTH) {
				memcpy(sqlstate, p, MYSQLND_SQLSTATE_LENGTH);
				p+= MYSQLND_SQLSTATE_LENGTH;
			} else {
				goto end;
			}
		}
		if ((buf_len - (p - buf)) > 0) {
			error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1));
			memcpy(error, p, error_msg_len);
		}
	}
end:
	sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
	error[error_msg_len]= '\0';

	DBG_RETURN(FAIL);


static enum_func_status
php_mysqlnd_auth_response_read(void * _packet, MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
	size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
	zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
	zend_uchar *p = buf;
	zend_uchar *begin = buf;
	unsigned long i;
	register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;

	DBG_ENTER("php_mysqlnd_auth_response_read");

	/* leave space for terminating safety \0 */
	buf_len--;
	PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
	BAIL_IF_NO_MORE_DATA;

	/*
	  zero-terminate the buffer for safety. We are sure there is place for the \0
	  because buf_len is -1 the size of the buffer pointed
	*/
	buf[packet->header.size] = '\0';

	/* Should be always 0x0 or ERROR_MARKER for error */
	packet->response_code = uint1korr(p);
	p++;
	BAIL_IF_NO_MORE_DATA;

	if (ERROR_MARKER == packet->response_code) {
		php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
										 packet->error, sizeof(packet->error),
										 &packet->error_no, packet->sqlstate
										 TSRMLS_CC);
		DBG_RETURN(PASS);
	}
	if (0xFE == packet->response_code) {
		/* Authentication Switch Response */
		if (packet->header.size > (size_t) (p - buf)) {
			packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
			packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
			p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */

			packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
			if (packet->new_auth_protocol_data_len) {
				packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
				memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
			}
			DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
			DBG_INF_FMT("Server salt : [%d][%.*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
		}
	} else {
		/* Everything was fine! */
		packet->affected_rows  = php_mysqlnd_net_field_length_ll(&p);
		BAIL_IF_NO_MORE_DATA;

		packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
		BAIL_IF_NO_MORE_DATA;

		packet->server_status = uint2korr(p);
		p+= 2;
		BAIL_IF_NO_MORE_DATA;

		packet->warning_count = uint2korr(p);
		p+= 2;
		BAIL_IF_NO_MORE_DATA;

		/* There is a message */
		if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
			packet->message_len = MIN(i, buf_len - (p - begin));
			packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
		} else {
			packet->message = NULL;
			packet->message_len = 0;
		}

		DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
					packet->affected_rows, packet->last_insert_id, packet->server_status,
					packet->warning_count);
	}

	DBG_RETURN(PASS);
premature_end:
	DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
	php_error_docref(NULL TSRMLS_CC, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
					 p - begin - packet->header.size);
	DBG_RETURN(FAIL);


  void Compute(OpKernelContext* context) override {
    FusedBatchNormGradOpBase<Device, T, U>::ComputeWithReservedSpace(context,
                                                                     false);
  }


Status ParseActivationMode(OpKernelConstruction* context,
                           FusedBatchNormActivationMode* activation_mode) {
  string activation_mode_str;
  TF_RETURN_IF_ERROR(context->GetAttr("activation_mode", &activation_mode_str));

  if (activation_mode_str == "Identity") {
    *activation_mode = FusedBatchNormActivationMode::kIdentity;
    return Status::OK();
  }
  if (activation_mode_str == "Relu") {
    *activation_mode = FusedBatchNormActivationMode::kRelu;
    return Status::OK();
  }
  return errors::InvalidArgument("Unsupported activation mode: ",
                                 activation_mode_str);
}


  void operator()(OpKernelContext* context, const Tensor& x_input,
                  const Tensor& scale_input, const Tensor& offset_input,
                  const Tensor& running_mean_input,
                  const Tensor& running_variance_input,
                  const Tensor* side_input, U epsilon, U exponential_avg_factor,
                  FusedBatchNormActivationMode activation_mode,
                  Tensor* y_output, Tensor* running_mean_output,
                  Tensor* running_var_output, Tensor* saved_batch_mean_output,
                  Tensor* saved_batch_var_output, TensorFormat tensor_format,
                  bool use_reserved_space) {
    OP_REQUIRES(context, side_input == nullptr,
                errors::Internal(
                    "The CPU implementation of FusedBatchNorm does not support "
                    "side input."));
    OP_REQUIRES(context,
                activation_mode == FusedBatchNormActivationMode::kIdentity,
                errors::Internal("The CPU implementation of FusedBatchNorm "
                                 "does not support activations."));

    if (use_reserved_space) {
      Tensor* dummy_reserve_space = nullptr;
      OP_REQUIRES_OK(context,
                     context->allocate_output(5, {}, &dummy_reserve_space));
      // Initialize the memory, to avoid sanitizer alerts.
      dummy_reserve_space->flat<U>()(0) = U();
    }
    Tensor transformed_x;
    Tensor transformed_y;
    if (tensor_format == FORMAT_NCHW) {
      const int64 in_batch = GetTensorDim(x_input, tensor_format, 'N');
      const int64 in_rows = GetTensorDim(x_input, tensor_format, 'H');
      const int64 in_cols = GetTensorDim(x_input, tensor_format, 'W');
      const int64 in_depths = GetTensorDim(x_input, tensor_format, 'C');
      OP_REQUIRES_OK(context, context->allocate_temp(
                                  DataTypeToEnum<T>::value,
                                  ShapeFromFormat(FORMAT_NHWC, in_batch,
                                                  in_rows, in_cols, in_depths),
                                  &transformed_x));
      OP_REQUIRES_OK(context, context->allocate_temp(
                                  DataTypeToEnum<T>::value,
                                  ShapeFromFormat(FORMAT_NHWC, in_batch,
                                                  in_rows, in_cols, in_depths),
                                  &transformed_y));
      // Perform NCHW to NHWC
      std::vector<int32> perm = {0, 2, 3, 1};
      OP_REQUIRES_OK(
          context, ::tensorflow::DoTranspose(context->eigen_device<CPUDevice>(),
                                             x_input, perm, &transformed_x));
    } else {
      transformed_x = x_input;
      transformed_y = *y_output;
    }
    typename TTypes<T, 4>::Tensor x(transformed_x.tensor<T, 4>());
    typename TTypes<U>::ConstVec scale(scale_input.vec<U>());
    typename TTypes<U>::ConstVec offset(offset_input.vec<U>());
    typename TTypes<U>::ConstVec old_mean(running_mean_input.vec<U>());
    typename TTypes<U>::ConstVec old_variance(running_variance_input.vec<U>());
    typename TTypes<T, 4>::Tensor y(transformed_y.tensor<T, 4>());
    typename TTypes<U>::Vec new_mean(running_mean_output->vec<U>());
    typename TTypes<U>::Vec new_variance(running_var_output->vec<U>());
    typename TTypes<U>::Vec saved_batch_mean(saved_batch_mean_output->vec<U>());
    typename TTypes<U>::Vec saved_batch_var(saved_batch_var_output->vec<U>());

    const CPUDevice& d = context->eigen_device<CPUDevice>();

    const int depth = x.dimension(3);
    const int size = x.size();
    const int rest_size = size / depth;
    Eigen::DSizes<Eigen::Index, 2> rest_by_depth(rest_size, depth);

#if !defined(EIGEN_HAS_INDEX_LIST)
    Eigen::DSizes<Eigen::Index, 2> one_by_depth(1, depth);
    Eigen::array<int, 1> reduce_dims({0});
    Eigen::array<int, 2> bcast_spec({rest_size, 1});
#else
    Eigen::IndexList<Eigen::type2index<1>, Eigen::Index> one_by_depth;
    one_by_depth.set(1, depth);
    Eigen::IndexList<Eigen::type2index<0>> reduce_dims;
    Eigen::IndexList<Eigen::Index, Eigen::type2index<1>> bcast_spec;
    bcast_spec.set(0, rest_size);
#endif

    auto x_rest_by_depth = x.reshape(rest_by_depth).template cast<U>();
    const int rest_size_minus_one = (rest_size > 1) ? (rest_size - 1) : 1;
    U rest_size_inv = static_cast<U>(1.0f / static_cast<U>(rest_size));
    // This adjustment is for Bessel's correction
    U rest_size_adjust =
        static_cast<U>(rest_size) / static_cast<U>(rest_size_minus_one);

    Eigen::Tensor<U, 1, Eigen::RowMajor> batch_mean(depth);
    Eigen::Tensor<U, 1, Eigen::RowMajor> batch_variance(depth);

    batch_mean.device(d) = (x_rest_by_depth.sum(reduce_dims) * rest_size_inv);
    auto x_centered = x_rest_by_depth -
                      batch_mean.reshape(one_by_depth).broadcast(bcast_spec);

    batch_variance.device(d) =
        x_centered.square().sum(reduce_dims) * rest_size_inv;
    auto scaling_factor = ((batch_variance + epsilon).rsqrt() * scale)
                              .eval()
                              .reshape(one_by_depth)
                              .broadcast(bcast_spec);
    auto x_scaled = x_centered * scaling_factor;
    auto x_shifted =
        (x_scaled + offset.reshape(one_by_depth).broadcast(bcast_spec))
            .template cast<T>();

    y.reshape(rest_by_depth).device(d) = x_shifted;
    if (exponential_avg_factor == U(1.0)) {
      saved_batch_var.device(d) = batch_variance;
      saved_batch_mean.device(d) = batch_mean;
      new_variance.device(d) = batch_variance * rest_size_adjust;
      new_mean.device(d) = batch_mean;
    } else {
      U one_minus_factor = U(1) - exponential_avg_factor;
      saved_batch_var.device(d) = batch_variance;
      saved_batch_mean.device(d) = batch_mean;
      new_variance.device(d) =
          one_minus_factor * old_variance +
          (exponential_avg_factor * rest_size_adjust) * batch_variance;
      new_mean.device(d) =
          one_minus_factor * old_mean + exponential_avg_factor * batch_mean;
    }

    if (tensor_format == FORMAT_NCHW) {
      // Perform NHWC to NCHW
      const std::vector<int32> perm = {0, 3, 1, 2};
      const Status s = ::tensorflow::DoTranspose(
          context->eigen_device<CPUDevice>(), transformed_y, perm, y_output);
      if (!s.ok()) {
        context->SetStatus(errors::InvalidArgument("Transpose failed: ", s));
      }
    }
  }


  CudnnBatchNormAllocatorInOutput(OpKernelContext* context, int output_index)
      : context_(context), output_index_(output_index) {}


  void Compute(OpKernelContext* context) override {
    FusedBatchNormOpBase<Device, T, U>::ComputeWithReservedSpace(context,
                                                                 false);
  }


  Tensor get_allocated_tensor(int index) const {
    return allocated_tensors_[index];
  }


void dns_server_unlink(DnsServer *s) {
        assert(s);
        assert(s->manager);

        /* This removes the specified server from the linked list of
         * servers, but any server might still stay around if it has
         * refs, for example from an ongoing transaction. */

        if (!s->linked)
                return;

        switch (s->type) {

        case DNS_SERVER_LINK:
                assert(s->link);
                assert(s->link->n_dns_servers > 0);
                LIST_REMOVE(servers, s->link->dns_servers, s);
                s->link->n_dns_servers--;
                break;

        case DNS_SERVER_SYSTEM:
                assert(s->manager->n_dns_servers > 0);
                LIST_REMOVE(servers, s->manager->dns_servers, s);
                s->manager->n_dns_servers--;
                break;

        case DNS_SERVER_FALLBACK:
                assert(s->manager->n_dns_servers > 0);
                LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
                s->manager->n_dns_servers--;
                break;
        default:
                assert_not_reached("Unknown server type");
        }

        s->linked = false;

        if (s->link && s->link->current_dns_server == s)
                link_set_dns_server(s->link, NULL);

        if (s->manager->current_dns_server == s)
                manager_set_dns_server(s->manager, NULL);

        /* No need to keep a default stream around anymore */
        dns_server_unref_stream(s);

        dns_server_unref(s);
}


static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
        _cleanup_free_ char *pretty = NULL;
        char key_str[DNS_RESOURCE_KEY_STRING_MAX];
        DnsZoneItem *z;

        assert(t);
        assert(p);

        if (manager_our_packet(t->scope->manager, p) != 0)
                return;

        (void) in_addr_to_string(p->family, &p->sender, &pretty);

        log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.",
                  t->id,
                  dns_resource_key_to_string(t->key, key_str, sizeof key_str),
                  dns_protocol_to_string(t->scope->protocol),
                  t->scope->link ? t->scope->link->name : "*",
                  af_to_name_short(t->scope->family),
                  strnull(pretty));

        /* RFC 4795, Section 4.1 says that the peer with the
         * lexicographically smaller IP address loses */
        if (memcmp(&p->sender, &p->destination, FAMILY_ADDRESS_SIZE(p->family)) >= 0) {
                log_debug("Peer has lexicographically larger IP address and thus lost in the conflict.");
                return;
        }

        log_debug("We have the lexicographically larger IP address and thus lost in the conflict.");

        t->block_gc++;

        while ((z = set_first(t->notify_zone_items))) {
                /* First, make sure the zone item drops the reference
                 * to us */
                dns_zone_item_probe_stop(z);

                /* Secondly, report this as conflict, so that we might
                 * look for a different hostname */
                dns_zone_item_conflict(z);
        }
        t->block_gc--;

        dns_transaction_gc(t);
}


void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, size_t size) {
        assert(s);

        if (protocol == IPPROTO_UDP) {
                if (s->possible_feature_level == level)
                        s->n_failed_udp = 0;
        } else if (protocol == IPPROTO_TCP) {
                if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(level)) {
                        if (s->possible_feature_level == level)
                                s->n_failed_tls = 0;
                } else {
                        if (s->possible_feature_level == level)
                                s->n_failed_tcp = 0;

                        /* Successful TCP connections are only useful to verify the TCP feature level. */
                        level = DNS_SERVER_FEATURE_LEVEL_TCP;
                }
        }

        /* If the RRSIG data is missing, then we can only validate EDNS0 at max */
        if (s->packet_rrsig_missing && level >= DNS_SERVER_FEATURE_LEVEL_DO)
                level = DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN : DNS_SERVER_FEATURE_LEVEL_EDNS0;

        /* If the OPT RR got lost, then we can only validate UDP at max */
        if (s->packet_bad_opt && level >= DNS_SERVER_FEATURE_LEVEL_EDNS0)
                level = DNS_SERVER_FEATURE_LEVEL_EDNS0 - 1;

        /* Even if we successfully receive a reply to a request announcing support for large packets,
                that does not mean we can necessarily receive large packets. */
        if (level == DNS_SERVER_FEATURE_LEVEL_LARGE)
                level = DNS_SERVER_FEATURE_LEVEL_LARGE - 1;

        dns_server_verified(s, level);

        /* Remember the size of the largest UDP packet we received from a server,
           we know that we can always announce support for packets with at least
           this size. */
        if (protocol == IPPROTO_UDP && s->received_udp_packet_max < size)
                s->received_udp_packet_max = size;
}


static int on_stream_complete(DnsStream *s, int error) {
        _cleanup_(dns_stream_unrefp) DnsStream *p = NULL;

        /* Do not let new transactions use this stream */
        if (s->server && s->server->stream == s)
                p = TAKE_PTR(s->server->stream);

        if (ERRNO_IS_DISCONNECT(error) && s->protocol != DNS_PROTOCOL_LLMNR) {
                log_debug_errno(error, "Connection failure for DNS TCP stream: %m");

                if (s->transactions) {
                        DnsTransaction *t;

                        t = s->transactions;
                        dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level);
                }
        }

        if (error != 0) {
                DnsTransaction *t, *n;

                LIST_FOREACH_SAFE(transactions_by_stream, t, n, s->transactions)
                        on_transaction_stream_error(t, error);
        }

        return 0;
}


int dns_transaction_go(DnsTransaction *t) {
        usec_t ts;
        int r;
        char key_str[DNS_RESOURCE_KEY_STRING_MAX];

        assert(t);

        /* Returns > 0 if the transaction is now pending, returns 0 if could be processed immediately and has finished
         * now. */

        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);

        r = dns_transaction_prepare(t, ts);
        if (r <= 0)
                return r;

        log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.",
                  t->id,
                  dns_resource_key_to_string(t->key, key_str, sizeof key_str),
                  dns_protocol_to_string(t->scope->protocol),
                  t->scope->link ? t->scope->link->name : "*",
                  af_to_name_short(t->scope->family));

        if (!t->initial_jitter_scheduled &&
            IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
                usec_t jitter, accuracy;

                /* RFC 4795 Section 2.7 suggests all queries should be
                 * delayed by a random time from 0 to JITTER_INTERVAL. */

                t->initial_jitter_scheduled = true;

                random_bytes(&jitter, sizeof(jitter));

                switch (t->scope->protocol) {

                case DNS_PROTOCOL_LLMNR:
                        jitter %= LLMNR_JITTER_INTERVAL_USEC;
                        accuracy = LLMNR_JITTER_INTERVAL_USEC;
                        break;

                case DNS_PROTOCOL_MDNS:
                        jitter %= MDNS_JITTER_RANGE_USEC;
                        jitter += MDNS_JITTER_MIN_USEC;
                        accuracy = MDNS_JITTER_RANGE_USEC;
                        break;
                default:
                        assert_not_reached("bad protocol");
                }

                r = sd_event_add_time(
                                t->scope->manager->event,
                                &t->timeout_event_source,
                                clock_boottime_or_monotonic(),
                                ts + jitter, accuracy,
                                on_transaction_timeout, t);
                if (r < 0)
                        return r;

                (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");

                t->n_attempts = 0;
                t->next_attempt_after = ts;
                t->state = DNS_TRANSACTION_PENDING;

                log_debug("Delaying %s transaction for " USEC_FMT "us.", dns_protocol_to_string(t->scope->protocol), jitter);
                return 0;
        }

        /* Otherwise, we need to ask the network */
        r = dns_transaction_make_packet(t);
        if (r < 0)
                return r;

        if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
            (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 ||
             dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) {

                /* RFC 4795, Section 2.4. says reverse lookups shall
                 * always be made via TCP on LLMNR */
                r = dns_transaction_emit_tcp(t);
        } else {
                /* Try via UDP, and if that fails due to large size or lack of
                 * support try via TCP */
                r = dns_transaction_emit_udp(t);
                if (r == -EMSGSIZE)
                        log_debug("Sending query via TCP since it is too large.");
                else if (r == -EAGAIN)
                        log_debug("Sending query via TCP since UDP isn't supported.");
                if (IN_SET(r, -EMSGSIZE, -EAGAIN))
                        r = dns_transaction_emit_tcp(t);
        }

        if (r == -ESRCH) {
                /* No servers to send this to? */
                dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS);
                return 0;
        }
        if (r == -EOPNOTSUPP) {
                /* Tried to ask for DNSSEC RRs, on a server that doesn't do DNSSEC  */
                dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED);
                return 0;
        }
        if (t->scope->protocol == DNS_PROTOCOL_LLMNR && ERRNO_IS_DISCONNECT(-r)) {
                /* On LLMNR, if we cannot connect to a host via TCP when doing reverse lookups. This means we cannot
                 * answer this request with this protocol. */
                dns_transaction_complete(t, DNS_TRANSACTION_NOT_FOUND);
                return 0;
        }
        if (r < 0) {
                if (t->scope->protocol != DNS_PROTOCOL_DNS)
                        return r;

                /* Couldn't send? Try immediately again, with a new server */
                dns_scope_next_dns_server(t->scope);

                return dns_transaction_go(t);
        }

        ts += transaction_get_resend_timeout(t);

        r = sd_event_add_time(
                        t->scope->manager->event,
                        &t->timeout_event_source,
                        clock_boottime_or_monotonic(),
                        ts, 0,
                        on_transaction_timeout, t);
        if (r < 0)
                return r;

        (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");

        t->state = DNS_TRANSACTION_PENDING;
        t->next_attempt_after = ts;

        return 1;
}


static int dnssec_validate_records(
                DnsTransaction *t,
                Phase phase,
                bool *have_nsec,
                DnsAnswer **validated) {

        DnsResourceRecord *rr;
        int r;

        /* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */

        DNS_ANSWER_FOREACH(rr, t->answer) {
                DnsResourceRecord *rrsig = NULL;
                DnssecResult result;

                switch (rr->key->type) {
                case DNS_TYPE_RRSIG:
                        continue;

                case DNS_TYPE_DNSKEY:
                        /* We validate DNSKEYs only in the DNSKEY and ALL phases */
                        if (phase == DNSSEC_PHASE_NSEC)
                                continue;
                        break;

                case DNS_TYPE_NSEC:
                case DNS_TYPE_NSEC3:
                        *have_nsec = true;

                        /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */
                        if (phase == DNSSEC_PHASE_DNSKEY)
                                continue;
                        break;

                default:
                        /* We validate all other RRs only in the ALL phases */
                        if (phase != DNSSEC_PHASE_ALL)
                                continue;
                }

                r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig);
                if (r < 0)
                        return r;

                log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));

                if (result == DNSSEC_VALIDATED) {

                        if (rr->key->type == DNS_TYPE_DNSKEY) {
                                /* If we just validated a DNSKEY RRset, then let's add these keys to
                                 * the set of validated keys for this transaction. */

                                r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
                                if (r < 0)
                                        return r;

                                /* Some of the DNSKEYs we just added might already have been revoked,
                                 * remove them again in that case. */
                                r = dns_transaction_invalidate_revoked_keys(t);
                                if (r < 0)
                                        return r;
                        }

                        /* Add the validated RRset to the new list of validated
                         * RRsets, and remove it from the unvalidated RRsets.
                         * We mark the RRset as authenticated and cacheable. */
                        r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE);
                        if (r < 0)
                                return r;

                        manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key);

                        /* Exit the loop, we dropped something from the answer, start from the beginning */
                        return 1;
                }

                /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as
                 * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet,
                 * we cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */
                if (phase != DNSSEC_PHASE_ALL)
                        continue;

                if (result == DNSSEC_VALIDATED_WILDCARD) {
                        bool authenticated = false;
                        const char *source;

                        /* This RRset validated, but as a wildcard. This means we need
                         * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists. */

                        /* First step, determine the source of synthesis */
                        r = dns_resource_record_source(rrsig, &source);
                        if (r < 0)
                                return r;

                        r = dnssec_test_positive_wildcard(*validated,
                                                          dns_resource_key_name(rr->key),
                                                          source,
                                                          rrsig->rrsig.signer,
                                                          &authenticated);

                        /* Unless the NSEC proof showed that the key really doesn't exist something is off. */
                        if (r == 0)
                                result = DNSSEC_INVALID;
                        else {
                                r = dns_answer_move_by_key(validated, &t->answer, rr->key,
                                                           authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0);
                                if (r < 0)
                                        return r;

                                manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key);

                                /* Exit the loop, we dropped something from the answer, start from the beginning */
                                return 1;
                        }
                }

                if (result == DNSSEC_NO_SIGNATURE) {
                        r = dns_transaction_requires_rrsig(t, rr);
                        if (r < 0)
                                return r;
                        if (r == 0) {
                                /* Data does not require signing. In that case, just copy it over,
                                 * but remember that this is by no means authenticated. */
                                r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
                                if (r < 0)
                                        return r;

                                manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
                                return 1;
                        }

                        r = dns_transaction_known_signed(t, rr);
                        if (r < 0)
                                return r;
                        if (r > 0) {
                                /* This is an RR we know has to be signed. If it isn't this means
                                 * the server is not attaching RRSIGs, hence complain. */

                                dns_server_packet_rrsig_missing(t->server, t->current_feature_level);

                                if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) {

                                        /* Downgrading is OK? If so, just consider the information unsigned */

                                        r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
                                        if (r < 0)
                                                return r;

                                        manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
                                        return 1;
                                }

                                /* Otherwise, fail */
                                t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
                                return 0;
                        }

                        r = dns_transaction_in_private_tld(t, rr->key);
                        if (r < 0)
                                return r;
                        if (r > 0) {
                                char s[DNS_RESOURCE_KEY_STRING_MAX];

                                /* The data is from a TLD that is proven not to exist, and we are in downgrade
                                 * mode, hence ignore the fact that this was not signed. */

                                log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.",
                                         dns_resource_key_to_string(rr->key, s, sizeof s));

                                r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
                                if (r < 0)
                                        return r;

                                manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
                                return 1;
                        }
                }

                if (IN_SET(result,
                           DNSSEC_MISSING_KEY,
                           DNSSEC_SIGNATURE_EXPIRED,
                           DNSSEC_UNSUPPORTED_ALGORITHM)) {

                        r = dns_transaction_dnskey_authenticated(t, rr);
                        if (r < 0 && r != -ENXIO)
                                return r;
                        if (r == 0) {
                                /* The DNSKEY transaction was not authenticated, this means there's
                                 * no DS for this, which means it's OK if no keys are found for this signature. */

                                r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
                                if (r < 0)
                                        return r;

                                manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
                                return 1;
                        }
                }

                r = dns_transaction_is_primary_response(t, rr);
                if (r < 0)
                        return r;
                if (r > 0) {
                        /* Look for a matching DNAME for this CNAME */
                        r = dns_answer_has_dname_for_cname(t->answer, rr);
                        if (r < 0)
                                return r;
                        if (r == 0) {
                                /* Also look among the stuff we already validated */
                                r = dns_answer_has_dname_for_cname(*validated, rr);
                                if (r < 0)
                                        return r;
                        }

                        if (r == 0) {
                                if (IN_SET(result,
                                           DNSSEC_INVALID,
                                           DNSSEC_SIGNATURE_EXPIRED,
                                           DNSSEC_NO_SIGNATURE))
                                        manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
                                else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
                                        manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);

                                /* This is a primary response to our question, and it failed validation.
                                 * That's fatal. */
                                t->answer_dnssec_result = result;
                                return 0;
                        }

                        /* This is a primary response, but we do have a DNAME RR
                         * in the RR that can replay this CNAME, hence rely on
                         * that, and we can remove the CNAME in favour of it. */
                }

                /* This is just some auxiliary data. Just remove the RRset and continue. */
                r = dns_answer_remove_by_key(&t->answer, rr->key);
                if (r < 0)
                        return r;

                /* We dropped something from the answer, start from the beginning. */
                return 1;
        }

        return 2; /* Finito. */
}


static int dns_transaction_pick_server(DnsTransaction *t) {
        DnsServer *server;

        assert(t);
        assert(t->scope->protocol == DNS_PROTOCOL_DNS);

        /* Pick a DNS server and a feature level for it. */

        server = dns_scope_get_dns_server(t->scope);
        if (!server)
                return -ESRCH;

        /* If we changed the server invalidate the feature level clamping, as the new server might have completely
         * different properties. */
        if (server != t->server)
                t->clamp_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID;

        t->current_feature_level = dns_server_possible_feature_level(server);

        /* Clamp the feature level if that is requested. */
        if (t->clamp_feature_level != _DNS_SERVER_FEATURE_LEVEL_INVALID &&
            t->current_feature_level > t->clamp_feature_level)
                t->current_feature_level = t->clamp_feature_level;

        log_debug("Using feature level %s for transaction %u.", dns_server_feature_level_to_string(t->current_feature_level), t->id);

        if (server == t->server)
                return 0;

        dns_server_unref(t->server);
        t->server = dns_server_ref(server);

        t->n_picked_servers ++;

        log_debug("Using DNS server %s for transaction %u.", dns_server_string(t->server), t->id);

        return 1;
}


static void dns_server_hash_func(const DnsServer *s, struct siphash *state) {
        assert(s);

        siphash24_compress(&s->family, sizeof(s->family), state);
        siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
        siphash24_compress(&s->ifindex, sizeof(s->ifindex), state);
}


void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
        DnsQueryCandidate *c;
        DnsZoneItem *z;
        DnsTransaction *d;
        const char *st;
        char key_str[DNS_RESOURCE_KEY_STRING_MAX];

        assert(t);
        assert(!DNS_TRANSACTION_IS_LIVE(state));

        if (state == DNS_TRANSACTION_DNSSEC_FAILED) {
                dns_resource_key_to_string(t->key, key_str, sizeof key_str);

                log_struct(LOG_NOTICE,
                           "MESSAGE_ID=" SD_MESSAGE_DNSSEC_FAILURE_STR,
                           LOG_MESSAGE("DNSSEC validation failed for question %s: %s", key_str, dnssec_result_to_string(t->answer_dnssec_result)),
                           "DNS_TRANSACTION=%" PRIu16, t->id,
                           "DNS_QUESTION=%s", key_str,
                           "DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result),
                           "DNS_SERVER=%s", dns_server_string(t->server),
                           "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level));
        }

        /* Note that this call might invalidate the query. Callers
         * should hence not attempt to access the query or transaction
         * after calling this function. */

        if (state == DNS_TRANSACTION_ERRNO)
                st = errno_to_name(t->answer_errno);
        else
                st = dns_transaction_state_to_string(state);

        log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).",
                  t->id,
                  dns_resource_key_to_string(t->key, key_str, sizeof key_str),
                  dns_protocol_to_string(t->scope->protocol),
                  t->scope->link ? t->scope->link->name : "*",
                  af_to_name_short(t->scope->family),
                  st,
                  t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source),
                  t->answer_authenticated ? "authenticated" : "unsigned");

        t->state = state;

        dns_transaction_close_connection(t);
        dns_transaction_stop_timeout(t);

        /* Notify all queries that are interested, but make sure the
         * transaction isn't freed while we are still looking at it */
        t->block_gc++;

        SET_FOREACH_MOVE(c, t->notify_query_candidates_done, t->notify_query_candidates)
                dns_query_candidate_notify(c);
        SWAP_TWO(t->notify_query_candidates, t->notify_query_candidates_done);

        SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items)
                dns_zone_item_notify(z);
        SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done);
        if (t->probing && t->state == DNS_TRANSACTION_ATTEMPTS_MAX_REACHED)
                (void) dns_scope_announce(t->scope, false);

        SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions)
                dns_transaction_notify(d, t);
        SWAP_TWO(t->notify_transactions, t->notify_transactions_done);

        t->block_gc--;
        dns_transaction_gc(t);
}


static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) {
        int r;

        assert(t);

        /* Checks whether the answer is positive, i.e. either a direct
         * answer to the question, or a CNAME/DNAME for it */

        r = dns_answer_match_key(t->answer, t->key, flags);
        if (r != 0)
                return r;

        r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags);
        if (r != 0)
                return r;

        return false;
}


static DnsServer* dns_server_free(DnsServer *s)  {
        assert(s);

        dns_server_unref_stream(s);

#if ENABLE_DNS_OVER_TLS
        dnstls_server_free(s);
#endif

        free(s->server_string);
        return mfree(s);
}


DnsServer *manager_get_dns_server(Manager *m) {
        Link *l;
        assert(m);

        /* Try to read updates resolv.conf */
        manager_read_resolv_conf(m);

        /* If no DNS server was chosen so far, pick the first one */
        if (!m->current_dns_server)
                manager_set_dns_server(m, m->dns_servers);

        if (!m->current_dns_server) {
                bool found = false;
                Iterator i;

                /* No DNS servers configured, let's see if there are
                 * any on any links. If not, we use the fallback
                 * servers */

                HASHMAP_FOREACH(l, m->links, i)
                        if (l->dns_servers) {
                                found = true;
                                break;
                        }

                if (!found)
                        manager_set_dns_server(m, m->fallback_dns_servers);
        }

        return m->current_dns_server;
}


static void dns_transaction_stop_timeout(DnsTransaction *t) {
        assert(t);

        t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
}


void ACSequentialScan::Restart(void)
{
#if ACCUSOFT_CODE
  int i;

  for(i = 0;i < m_ucCount;i++) {
    m_lDC[i]         = 0;
    m_lDiff[i]       = 0;
  }
  for(i = 0;i < 4;i++) {
    m_Context[i].Init();
  }

  m_Coder.OpenForRead(m_Coder.ByteStreamOf(),m_Coder.ChecksumOf());
#endif
}


bool ACLosslessScan::StartMCURow(void)
{
#if ACCUSOFT_CODE
  return m_pLineCtrl->StartMCUQuantizerRow(m_pScan);
#else
  return false;
#endif
}


void ACLosslessScan::Flush(bool)
{
#if ACCUSOFT_CODE
  int i;

  m_Coder.Flush();

  for(i = 0;i < m_ucCount;i++) {
    memset(m_plDa[i],0,sizeof(LONG) * m_ucMCUHeight[i]);
    memset(m_plDb[i],0,sizeof(LONG) * m_ucMCUWidth[i] * m_ulWidth[i]); // Reset conditioning to the top
  }
  for(i = 0;i < 4;i++) {
    m_Context[i].Init();
  }

  PredictiveScan::FlushOnMarker();

  m_Coder.OpenForWrite(m_Coder.ByteStreamOf(),m_Coder.ChecksumOf());
#endif
}


static void aio_fput_routine(struct work_struct *data)
{
	spin_lock_irq(&fput_lock);
	while (likely(!list_empty(&fput_head))) {
		struct kiocb *req = list_kiocb(fput_head.next);
		struct kioctx *ctx = req->ki_ctx;

		list_del(&req->ki_list);
		spin_unlock_irq(&fput_lock);

		/* Complete the fput(s) */
		if (req->ki_filp != NULL)
			fput(req->ki_filp);

		/* Link the iocb into the context's free list */
		rcu_read_lock();
		spin_lock_irq(&ctx->ctx_lock);
		really_put_req(ctx, req);
		/*
		 * at that point ctx might've been killed, but actual
		 * freeing is RCU'd
		 */
		spin_unlock_irq(&ctx->ctx_lock);
		rcu_read_unlock();

		spin_lock_irq(&fput_lock);
	}
	spin_unlock_irq(&fput_lock);
}


static void ctx_rcu_free(struct rcu_head *head)
{
	struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
	kmem_cache_free(kioctx_cachep, ctx);
}


static void aio_free_ring(struct kioctx *ctx)
{
	struct aio_ring_info *info = &ctx->ring_info;
	long i;

	for (i=0; i<info->nr_pages; i++)
		put_page(info->ring_pages[i]);

	if (info->mmap_size) {
		BUG_ON(ctx->mm != current->mm);
		vm_munmap(info->mmap_base, info->mmap_size);
	}

	if (info->ring_pages && info->ring_pages != info->internal_pages)
		kfree(info->ring_pages);
	info->ring_pages = NULL;
	info->nr = 0;
}


SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp)
{
	struct kioctx *ioctx = NULL;
	unsigned long ctx;
	long ret;

	ret = get_user(ctx, ctxp);
	if (unlikely(ret))
		goto out;

	ret = -EINVAL;
	if (unlikely(ctx || nr_events == 0)) {
		pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n",
		         ctx, nr_events);
		goto out;
	}

	ioctx = ioctx_alloc(nr_events);
	ret = PTR_ERR(ioctx);
	if (!IS_ERR(ioctx)) {
		ret = put_user(ioctx->user_id, ctxp);
		if (ret)
			io_destroy(ioctx);
		put_ioctx(ioctx);
	}

out:
	return ret;
}


static int __init aio_setup(void)
{
	kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
	kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);

	aio_wq = alloc_workqueue("aio", 0, 1);	/* used to limit concurrency */
	BUG_ON(!aio_wq);

	pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page));

	return 0;
}


TEST(AsyncSSLSocketTest, SSLAcceptRunnerBasic) {
  EventBase eventBase;
  auto clientCtx = std::make_shared<SSLContext>();
  auto serverCtx = std::make_shared<SSLContext>();
  serverCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
  serverCtx->loadPrivateKey(kTestKey);
  serverCtx->loadCertificate(kTestCert);

  clientCtx->setVerificationOption(SSLContext::SSLVerifyPeerEnum::VERIFY);
  clientCtx->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
  clientCtx->loadTrustedCertificates(kTestCA);

  NetworkSocket fds[2];
  getfds(fds);

  AsyncSSLSocket::UniquePtr clientSock(
      new AsyncSSLSocket(clientCtx, &eventBase, fds[0], false));
  AsyncSSLSocket::UniquePtr serverSock(
      new AsyncSSLSocket(serverCtx, &eventBase, fds[1], true));

  serverCtx->sslAcceptRunner(std::make_unique<SSLAcceptEvbRunner>(&eventBase));

  SSLHandshakeClient client(std::move(clientSock), true, true);
  SSLHandshakeServer server(std::move(serverSock), true, true);

  eventBase.loop();

  EXPECT_TRUE(client.handshakeSuccess_);
  EXPECT_FALSE(client.handshakeError_);
  EXPECT_LE(0, client.handshakeTime.count());
  EXPECT_TRUE(server.handshakeSuccess_);
  EXPECT_FALSE(server.handshakeError_);
  EXPECT_LE(0, server.handshakeTime.count());
}


void AsyncSSLSocket::invokeHandshakeErr(const AsyncSocketException& ex) {
  handshakeEndTime_ = std::chrono::steady_clock::now();
  if (handshakeCallback_ != nullptr) {
    HandshakeCB* callback = handshakeCallback_;
    handshakeCallback_ = nullptr;
    callback->handshakeErr(this, ex);
  }
}


void AsyncSSLSocket::shutdownWriteNow() {
  closeNow();
}


  void readEOF() noexcept override {
    ReadCallbackBase::readEOF();
    setState(STATE_SUCCEEDED);
  }


  void getReadBuffer(void** bufReturn, size_t* lenReturn) override {
    *bufReturn = buf_.data();
    *lenReturn = buf_.size();
  }


  SSLHandshakeClientDoVerify(
      AsyncSSLSocket::UniquePtr socket,
      bool preverifyResult,
      bool verifyResult)
      : SSLHandshakeBase(std::move(socket), preverifyResult, verifyResult) {
    socket_->sslConn(
        this,
        std::chrono::milliseconds::zero(),
        folly::SSLContext::SSLVerifyPeerEnum::VERIFY);
  }


void AsyncSSLSocket::setSSLSession(SSL_SESSION* session, bool takeOwnership) {
  if (sslSession_) {
    SSL_SESSION_free(sslSession_);
  }
  sslSession_ = session;
  if (!takeOwnership && session != nullptr) {
    // Increment the reference count
    // This API exists in BoringSSL and OpenSSL 1.1.0
    SSL_SESSION_up_ref(session);
  }
}


void AsyncSSLSocket::checkForImmediateRead() noexcept {
  // openssl may have buffered data that it read from the socket already.
  // In this case we have to process it immediately, rather than waiting for
  // the socket to become readable again.
  if (ssl_ != nullptr && SSL_pending(ssl_.get()) > 0) {
    AsyncSocket::handleRead();
  } else {
    AsyncSocket::checkForImmediateRead();
  }
}


void AsyncSSLSocket::enableClientHelloParsing() {
  parseClientHello_ = true;
  clientHelloInfo_ = std::make_unique<ssl::ClientHelloInfo>();
}


  void getReadBuffer(void** bufReturn, size_t* lenReturn) override {
    *lenReturn = sizeof(buf);
    *bufReturn = buf;
  }


static BIO_METHOD* getSSLBioMethod() {
  static auto const instance = OpenSSLUtils::newSocketBioMethod().release();
  return instance;
}


  void readDataAvailable(size_t /* len */) noexcept override {
    // This should never to called.
    FAIL();
  }


  void handshakeSuc(AsyncSSLSocket*) noexcept override {
    // Wait 10ms before reading, so the client's writes will initially block.
    socket_->getEventBase()->tryRunAfterDelay(
        [this] { socket_->setReadCB(this); }, 10);
  }


Buffer(char* buf, size_t len) : buffer(buf), length(len) {}


  CloseNotifyConnector(EventBase* evb, const SocketAddress& addr) {
    evb_ = evb;
    ssl_ = AsyncSSLSocket::newSocket(std::make_shared<SSLContext>(), evb_);
    ssl_->connect(this, addr);
  }


  void connAccepted(
      const std::shared_ptr<folly::AsyncSSLSocket>& s) noexcept override {
    auto sock = std::static_pointer_cast<AsyncSSLSocket>(s);

    std::cerr << "SSLServerAcceptCallbackDelay::connAccepted" << std::endl;
    auto fd = sock->getNetworkSocket();

#ifndef TCP_NOPUSH
    {
      // The accepted connection should already have TCP_NODELAY set
      int value;
      socklen_t valueLength = sizeof(value);
      int rc = netops::getsockopt(
          fd, IPPROTO_TCP, TCP_NODELAY, &value, &valueLength);
      EXPECT_EQ(rc, 0);
      EXPECT_EQ(value, 1);
    }
#endif

    // Unset the TCP_NODELAY option.
    int value = 0;
    socklen_t valueLength = sizeof(value);
    int rc =
        netops::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, valueLength);
    EXPECT_EQ(rc, 0);

    rc = netops::getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &value, &valueLength);
    EXPECT_EQ(rc, 0);
    EXPECT_EQ(value, 0);

    SSLServerAcceptCallback::connAccepted(sock);
  }


static int newCloseCb(SSL* ssl, SSL_SESSION*) {
  AsyncSSLSocket::getFromSSL(ssl)->closeNow();
  return 1;
}


  void getReadBuffer(void** /* bufReturn */, size_t* lenReturn) override {
    *lenReturn = 0;
  }


TEST(AsyncSSLSocketTest, EarlyCloseNotify) {
  WriteOnEofReadCallback readCallback(nullptr);
  HandshakeCallback handshakeCallback(&readCallback);
  SSLServerAcceptCallback acceptCallback(&handshakeCallback);
  TestSSLServer server(&acceptCallback);

  EventBase eventBase;
  CloseNotifyConnector cnc(&eventBase, server.getAddress());

  eventBase.loop();
}


  ConnectTimeoutCallback() : SSLServerAcceptCallbackBase(nullptr) {
    // We don't care if we get invoked or not.
    // The client may time out and give up before connAccepted() is even
    // called.
    state = STATE_SUCCEEDED;
  }


  folly::WriteFlags getObservedWriteFlags() {
    return observedWriteFlags_;
  }


void writeSuccess() noexcept override {}


  void SetUp() override {
    getctx(clientCtx, serverCtx);
  }


size_t AsyncSSLSocket::getRawBytesWritten() const {
  // The bio(s) in the write path are in a chain
  // each bio flushes to the next and finally written into the socket
  // to get the rawBytesWritten on the socket,
  // get the write bytes of the last bio
  BIO* b;
  if (!ssl_ || !(b = SSL_get_wbio(ssl_.get()))) {
    return 0;
  }
  BIO* next = BIO_next(b);
  while (next != nullptr) {
    b = next;
    next = BIO_next(b);
  }

  return BIO_number_written(b);
}


  explicit HandshakeTimeoutCallback(HandshakeCallback* hcb)
      : SSLServerAcceptCallbackBase(hcb) {}


  Status GetMap(OpKernelContext* ctx, bool is_writing,
                SparseTensorsMap** sparse_tensors_map) {
    mutex_lock l(mu_);

    if (sparse_tensors_map_) {
      *sparse_tensors_map = sparse_tensors_map_;
      return Status::OK();
    }

    TF_RETURN_IF_ERROR(cinfo_.Init(ctx->resource_manager(), def(),
                                   is_writing /* use_node_name_as_default */));

    CreatorCallback sparse_tensors_map_creator = [this](SparseTensorsMap** c) {
      SparseTensorsMap* map = new SparseTensorsMap(cinfo_.name());
      *c = map;
      return Status::OK();
    };

    TF_RETURN_IF_ERROR(
        cinfo_.resource_manager()->LookupOrCreate<SparseTensorsMap>(
            cinfo_.container(), cinfo_.name(), &sparse_tensors_map_,
            sparse_tensors_map_creator));

    *sparse_tensors_map = sparse_tensors_map_;
    return Status::OK();
  }


  explicit TakeManySparseFromTensorsMapOp(OpKernelConstruction* context)
      : SparseTensorAccessingOp(context) {}


void kvm_register_irq_ack_notifier(struct kvm *kvm,
				   struct kvm_irq_ack_notifier *kian)
{
	mutex_lock(&kvm->irq_lock);
	hlist_add_head_rcu(&kian->link, &kvm->irq_ack_notifier_list);
	mutex_unlock(&kvm->irq_lock);
	kvm_arch_post_irq_ack_notifier_list_update(kvm);
}


kvm_eventfd_init(struct kvm *kvm)
{
#ifdef CONFIG_HAVE_KVM_IRQFD
	spin_lock_init(&kvm->irqfds.lock);
	INIT_LIST_HEAD(&kvm->irqfds.items);
	INIT_LIST_HEAD(&kvm->irqfds.resampler_list);
	mutex_init(&kvm->irqfds.resampler_lock);
#endif
	INIT_LIST_HEAD(&kvm->ioeventfds);
}


static const Mech* negotiate_GetMechByOID(const WinPrAsn1_OID* oid)
{
	WINPR_ASSERT(oid);

	WinPrAsn1_OID testOid = *oid;

	if (sspi_gss_oid_compare(&testOid, &kerberos_wrong_OID))
	{
		testOid.len = kerberos_OID.len;
		testOid.data = kerberos_OID.data;
	}

	for (size_t i = 0; i < MECH_COUNT; i++)
	{
		if (sspi_gss_oid_compare(&testOid, MechTable[i].oid))
			return &MechTable[i];
	}
	return NULL;
}


static void kerberos_log_msg(krb5_context ctx, krb5_error_code code)
{
	const char* msg = krb5_get_error_message(ctx, code);
	WLog_ERR(TAG, msg);
	krb5_free_error_message(ctx, msg);
}


BOOL nla_send(rdpNla* nla)
{
	BOOL rc = FALSE;
	wStream* s = NULL;
	size_t length;
	WinPrAsn1Encoder* enc;
	WinPrAsn1_OctetString octet_string;

	WINPR_ASSERT(nla);

	enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
	if (!enc)
		return FALSE;

	/* TSRequest */
	WLog_DBG(TAG, "----->> sending...");
	if (!WinPrAsn1EncSeqContainer(enc))
		goto fail;

	/* version [0] INTEGER */
	WLog_DBG(TAG, "   ----->> protocol version %" PRIu32, nla->version);
	if (!WinPrAsn1EncContextualInteger(enc, 0, nla->version))
		goto fail;

	/* negoTokens [1] SEQUENCE OF SEQUENCE */
	if (nla->negoToken.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> auth info");
		if (!WinPrAsn1EncContextualSeqContainer(enc, 1) || !WinPrAsn1EncSeqContainer(enc))
			goto fail;

		/* negoToken [0] OCTET STRING */
		octet_string.data = nla->negoToken.pvBuffer;
		octet_string.len = nla->negoToken.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 0, &octet_string))
			goto fail;

		/* End negoTokens (SEQUENCE OF SEQUENCE) */
		if (!WinPrAsn1EncEndContainer(enc) || !WinPrAsn1EncEndContainer(enc))
			goto fail;
	}

	/* authInfo [2] OCTET STRING */
	if (nla->authInfo.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> public key auth");
		octet_string.data = nla->authInfo.pvBuffer;
		octet_string.len = nla->authInfo.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 2, &octet_string))
			goto fail;
	}

	/* pubKeyAuth [3] OCTET STRING */
	if (nla->pubKeyAuth.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> public key auth");
		octet_string.data = nla->pubKeyAuth.pvBuffer;
		octet_string.len = nla->pubKeyAuth.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 3, &octet_string))
			goto fail;
	}

	/* errorCode [4] INTEGER */
	if (nla->errorCode && nla->peerVersion >= 3 && nla->peerVersion != 5)
	{
		char buffer[1024];
		WLog_DBG(TAG, "   ----->> error code %s 0x%08" PRIx32,
		         winpr_strerror(nla->errorCode, buffer, sizeof(buffer)), nla->errorCode);
		if (!WinPrAsn1EncContextualInteger(enc, 4, nla->errorCode))
			goto fail;
	}

	/* clientNonce [5] OCTET STRING */
	if (nla->ClientNonce.cbBuffer > 0)
	{
		WLog_DBG(TAG, "   ----->> client nonce");
		octet_string.data = nla->ClientNonce.pvBuffer;
		octet_string.len = nla->ClientNonce.cbBuffer;
		if (!WinPrAsn1EncContextualOctetString(enc, 5, &octet_string))
			goto fail;
	}

	/* End TSRequest */
	if (!WinPrAsn1EncEndContainer(enc))
		goto fail;

	if (!WinPrAsn1EncStreamSize(enc, &length))
		goto fail;

	s = Stream_New(NULL, length);
	if (!s)
		goto fail;

	if (!WinPrAsn1EncToStream(enc, s))
		goto fail;

	WLog_DBG(TAG, "[%" PRIuz " bytes]", length);
	if (transport_write(nla->transport, s) < 0)
		goto fail;
	rc = TRUE;

fail:
	Stream_Free(s, TRUE);
	WinPrAsn1Encoder_Free(&enc);
	return rc;
}


int nla_server_recv(rdpNla* nla)
{
	int status = -1;
	wStream* s;

	WINPR_ASSERT(nla);

	s = nla_server_recv_stream(nla);
	if (!s)
		goto fail;
	status = nla_decode_ts_request(nla, s);

fail:
	Stream_Free(s, TRUE);
	return status;
}


static BOOL nla_sec_buffer_alloc_from_data(SecBuffer* buffer, const BYTE* data, size_t offset,
                                           size_t size)
{
	BYTE* pb;
	if (!nla_sec_buffer_alloc(buffer, offset + size))
		return FALSE;

	WINPR_ASSERT(buffer);
	pb = buffer->pvBuffer;
	memcpy(&pb[offset], data, size);
	return TRUE;
}


SECURITY_STATUS nla_decrypt_public_key_echo(rdpNla* nla)
{
	BYTE* public_key1 = NULL;
	BYTE* public_key2 = NULL;
	ULONG public_key_length = 0;
	size_t signature_length;
	SECURITY_STATUS status = SEC_E_INVALID_TOKEN;
	PSecBuffer pubKeyAuth;

	if (!nla)
		goto fail;

	pubKeyAuth = &nla->pubKeyAuth;

	signature_length = pubKeyAuth->cbBuffer - nla->PublicKey.cbBuffer;
	if ((pubKeyAuth->cbBuffer < nla->PublicKey.cbBuffer) ||
	    (signature_length > nla->ContextSizes.cbSecurityTrailer))
	{
		WLog_ERR(TAG, "unexpected pubKeyAuth buffer size: %" PRIu32 "", pubKeyAuth->cbBuffer);
		goto fail;
	}

	status = nla_decrypt(nla, pubKeyAuth, signature_length);
	if (status != SEC_E_OK)
		goto fail;

	public_key1 = &((BYTE*)nla->PublicKey.pvBuffer)[0];
	public_key2 = &((BYTE*)pubKeyAuth->pvBuffer)[pubKeyAuth->cbBuffer];

	if (!nla->server)
	{
		/* server echos the public key +1 */
		ap_integer_decrement_le(public_key2, public_key_length);
	}

	if (!public_key1 || !public_key2 || memcmp(public_key1, public_key2, public_key_length) != 0)
	{
		WLog_ERR(TAG, "Could not verify server's public key echo");
#if defined(WITH_DEBUG_NLA)
		WLog_ERR(TAG, "Expected (length = %" PRIu32 "):", public_key_length);
		winpr_HexDump(TAG, WLOG_ERROR, public_key1, public_key_length);
		WLog_ERR(TAG, "Actual (length = %" PRIu32 "):", public_key_length);
		winpr_HexDump(TAG, WLOG_ERROR, public_key2, public_key_length);
#endif
		status = SEC_E_MESSAGE_ALTERED; /* DO NOT SEND CREDENTIALS! */
		goto fail;
	}

	status = SEC_E_OK;
fail:

	return status;
}


BOOL nla_revert_to_self(rdpNla* nla)
{
	if (!nla)
		return FALSE;

	if (!nla->table || !nla->table->RevertSecurityContext)
		return FALSE;

	return (nla->table->RevertSecurityContext(&nla->context) == SEC_E_OK);
}


static void negotiate_ContextFree(NEGOTIATE_CONTEXT* context)
{
	WINPR_ASSERT(context);

	if (context->mechTypes.pvBuffer)
		free(context->mechTypes.pvBuffer);
	free(context);
}


static BOOL negotiate_read_neg_token(PSecBuffer input, NegToken* token)
{
	WinPrAsn1Decoder dec;
	WinPrAsn1Decoder dec2;
	WinPrAsn1_OID oid;
	WinPrAsn1_tagId contextual;
	WinPrAsn1_tag tag;
	size_t len;
	WinPrAsn1_OctetString octet_string;
	BOOL err;

	WINPR_ASSERT(input);
	WINPR_ASSERT(token);

	WinPrAsn1Decoder_InitMem(&dec, WINPR_ASN1_DER, input->pvBuffer, input->cbBuffer);

	if (!WinPrAsn1DecPeekTag(&dec, &tag))
		return FALSE;

	if (tag == 0x60)
	{
		/* initialContextToken [APPLICATION 0] */
		if (!WinPrAsn1DecReadApp(&dec, &tag, &dec2) || tag != 0)
			return FALSE;
		dec = dec2;

		/* thisMech OID */
		if (!WinPrAsn1DecReadOID(&dec, &oid, FALSE))
			return FALSE;

		if (!sspi_gss_oid_compare(&spnego_OID, &oid))
			return FALSE;

		/* [0] NegTokenInit */
		if (!WinPrAsn1DecReadContextualSequence(&dec, 0, &err, &dec2))
			return FALSE;

		token->init = TRUE;
	}
	/* [1] NegTokenResp */
	else if (!WinPrAsn1DecReadContextualSequence(&dec, 1, &err, &dec2))
		return FALSE;
	dec = dec2;

	WLog_DBG(TAG, token->init ? "Reading negTokenInit..." : "Reading negTokenResp...");

	/* Read NegTokenResp sequence members */
	do
	{
		if (!WinPrAsn1DecReadContextualTag(&dec, &contextual, &dec2))
			return FALSE;

		switch (contextual)
		{
			case 0:
				if (token->init)
				{
					/* mechTypes [0] MechTypeList */
					wStream s = WinPrAsn1DecGetStream(&dec2);
					token->mechTypes.BufferType = SECBUFFER_TOKEN;
					token->mechTypes.cbBuffer = Stream_Length(&s);
					token->mechTypes.pvBuffer = Stream_Buffer(&s);
					WLog_DBG(TAG, "\tmechTypes [0] (%li bytes)", token->mechTypes.cbBuffer);
				}
				else
				{
					/* negState [0] ENUMERATED */
					if (!WinPrAsn1DecReadEnumerated(&dec2, &token->negState))
						return FALSE;
					WLog_DBG(TAG, "\tnegState [0] (%d)", token->negState);
				}
				break;
			case 1:
				if (token->init)
				{
					/* reqFlags [1] ContextFlags BIT STRING (ignored) */
					if (!WinPrAsn1DecPeekTagAndLen(&dec2, &tag, &len) || (tag != ER_TAG_BIT_STRING))
						return FALSE;
					WLog_DBG(TAG, "\treqFlags [1] (%li bytes)", len);
				}
				else
				{
					/* supportedMech [1] MechType */
					if (!WinPrAsn1DecReadOID(&dec2, &token->supportedMech, FALSE))
						return FALSE;
					WLog_DBG(TAG, "\tsupportedMech [1] (%s)",
					         negotiate_mech_name(&token->supportedMech));
				}
				break;
			case 2:
				/* mechToken [2] OCTET STRING */
				if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE))
					return FALSE;
				token->mechToken.cbBuffer = octet_string.len;
				token->mechToken.pvBuffer = octet_string.data;
				token->mechToken.BufferType = SECBUFFER_TOKEN;
				WLog_DBG(TAG, "\tmechToken [2] (%li bytes)", octet_string.len);
				break;
			case 3:
				/* mechListMic [3] OCTET STRING */
				if (!WinPrAsn1DecReadOctetString(&dec2, &octet_string, FALSE))
					return FALSE;
				token->mic.cbBuffer = octet_string.len;
				token->mic.pvBuffer = octet_string.data;
				token->mic.BufferType = SECBUFFER_TOKEN;
				WLog_DBG(TAG, "\tmechListMIC [3] (%li bytes)", octet_string.len);
				break;
			default:
				WLog_ERR(TAG, "unknown contextual item %d", contextual);
				return FALSE;
		}
	} while (WinPrAsn1DecPeekTag(&dec, &tag));

	return TRUE;
}


static int ip6_finish_output2(struct sk_buff *skb)
{
	struct dst_entry *dst = skb_dst(skb);
	struct net_device *dev = dst->dev;
	struct neighbour *neigh;
	struct in6_addr *nexthop;
	int ret;

	skb->protocol = htons(ETH_P_IPV6);
	skb->dev = dev;

	if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));

		if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
		    ((mroute6_socket(dev_net(dev), skb) &&
		     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
		     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
					 &ipv6_hdr(skb)->saddr))) {
			struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);

			/* Do not check for IFF_ALLMULTI; multicast routing
			   is not supported in any case.
			 */
			if (newskb)
				NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
					newskb, NULL, newskb->dev,
					dev_loopback_xmit);

			if (ipv6_hdr(skb)->hop_limit == 0) {
				IP6_INC_STATS(dev_net(dev), idev,
					      IPSTATS_MIB_OUTDISCARDS);
				kfree_skb(skb);
				return 0;
			}
		}

		IP6_UPD_PO_STATS(dev_net(dev), idev, IPSTATS_MIB_OUTMCAST,
				skb->len);

		if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <=
		    IPV6_ADDR_SCOPE_NODELOCAL &&
		    !(dev->flags & IFF_LOOPBACK)) {
			kfree_skb(skb);
			return 0;
		}
	}

	rcu_read_lock_bh();
	nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr);
	neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop);
	if (unlikely(!neigh))
		neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false);
	if (!IS_ERR(neigh)) {
		ret = dst_neigh_output(dst, neigh, skb);
		rcu_read_unlock_bh();
		return ret;
	}
	rcu_read_unlock_bh();

	IP6_INC_STATS_BH(dev_net(dst->dev),
			 ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
	kfree_skb(skb);
	return -EINVAL;
}


int ip6_forward(struct sk_buff *skb)
{
	struct dst_entry *dst = skb_dst(skb);
	struct ipv6hdr *hdr = ipv6_hdr(skb);
	struct inet6_skb_parm *opt = IP6CB(skb);
	struct net *net = dev_net(dst->dev);
	u32 mtu;

	if (net->ipv6.devconf_all->forwarding == 0)
		goto error;

	if (skb_warn_if_lro(skb))
		goto drop;

	if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
		goto drop;
	}

	if (skb->pkt_type != PACKET_HOST)
		goto drop;

	skb_forward_csum(skb);

	/*
	 *	We DO NOT make any processing on
	 *	RA packets, pushing them to user level AS IS
	 *	without ane WARRANTY that application will be able
	 *	to interpret them. The reason is that we
	 *	cannot make anything clever here.
	 *
	 *	We are not end-node, so that if packet contains
	 *	AH/ESP, we cannot make anything.
	 *	Defragmentation also would be mistake, RA packets
	 *	cannot be fragmented, because there is no warranty
	 *	that different fragments will go along one path. --ANK
	 */
	if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) {
		if (ip6_call_ra_chain(skb, ntohs(opt->ra)))
			return 0;
	}

	/*
	 *	check and decrement ttl
	 */
	if (hdr->hop_limit <= 1) {
		/* Force OUTPUT device used as source address */
		skb->dev = dst->dev;
		icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
		IP6_INC_STATS_BH(net,
				 ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);

		kfree_skb(skb);
		return -ETIMEDOUT;
	}

	/* XXX: idev->cnf.proxy_ndp? */
	if (net->ipv6.devconf_all->proxy_ndp &&
	    pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
		int proxied = ip6_forward_proxy_check(skb);
		if (proxied > 0)
			return ip6_input(skb);
		else if (proxied < 0) {
			IP6_INC_STATS(net, ip6_dst_idev(dst),
				      IPSTATS_MIB_INDISCARDS);
			goto drop;
		}
	}

	if (!xfrm6_route_forward(skb)) {
		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
		goto drop;
	}
	dst = skb_dst(skb);

	/* IPv6 specs say nothing about it, but it is clear that we cannot
	   send redirects to source routed frames.
	   We don't send redirects to frames decapsulated from IPsec.
	 */
	if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) {
		struct in6_addr *target = NULL;
		struct inet_peer *peer;
		struct rt6_info *rt;

		/*
		 *	incoming and outgoing devices are the same
		 *	send a redirect.
		 */

		rt = (struct rt6_info *) dst;
		if (rt->rt6i_flags & RTF_GATEWAY)
			target = &rt->rt6i_gateway;
		else
			target = &hdr->daddr;

		peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1);

		/* Limit redirects both by destination (here)
		   and by source (inside ndisc_send_redirect)
		 */
		if (inet_peer_xrlim_allow(peer, 1*HZ))
			ndisc_send_redirect(skb, target);
		if (peer)
			inet_putpeer(peer);
	} else {
		int addrtype = ipv6_addr_type(&hdr->saddr);

		/* This check is security critical. */
		if (addrtype == IPV6_ADDR_ANY ||
		    addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
			goto error;
		if (addrtype & IPV6_ADDR_LINKLOCAL) {
			icmpv6_send(skb, ICMPV6_DEST_UNREACH,
				    ICMPV6_NOT_NEIGHBOUR, 0);
			goto error;
		}
	}

	mtu = dst_mtu(dst);
	if (mtu < IPV6_MIN_MTU)
		mtu = IPV6_MIN_MTU;

	if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
	    (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
		/* Again, force OUTPUT device used as source address */
		skb->dev = dst->dev;
		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
		IP6_INC_STATS_BH(net,
				 ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
		IP6_INC_STATS_BH(net,
				 ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
		kfree_skb(skb);
		return -EMSGSIZE;
	}

	if (skb_cow(skb, dst->dev->hard_header_len)) {
		IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
		goto drop;
	}

	hdr = ipv6_hdr(skb);

	/* Mangling hops number delayed to point after skb COW */

	hdr->hop_limit--;

	IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
	IP6_ADD_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
	return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
		       ip6_forward_finish);

error:
	IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
drop:
	kfree_skb(skb);
	return -EINVAL;
}


int ip6_push_pending_frames(struct sock *sk)
{
	struct sk_buff *skb, *tmp_skb;
	struct sk_buff **tail_skb;
	struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
	struct inet_sock *inet = inet_sk(sk);
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct net *net = sock_net(sk);
	struct ipv6hdr *hdr;
	struct ipv6_txoptions *opt = np->cork.opt;
	struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst;
	struct flowi6 *fl6 = &inet->cork.fl.u.ip6;
	unsigned char proto = fl6->flowi6_proto;
	int err = 0;

	if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL)
		goto out;
	tail_skb = &(skb_shinfo(skb)->frag_list);

	/* move skb->data to ip header from ext header */
	if (skb->data < skb_network_header(skb))
		__skb_pull(skb, skb_network_offset(skb));
	while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
		__skb_pull(tmp_skb, skb_network_header_len(skb));
		*tail_skb = tmp_skb;
		tail_skb = &(tmp_skb->next);
		skb->len += tmp_skb->len;
		skb->data_len += tmp_skb->len;
		skb->truesize += tmp_skb->truesize;
		tmp_skb->destructor = NULL;
		tmp_skb->sk = NULL;
	}

	/* Allow local fragmentation. */
	if (np->pmtudisc < IPV6_PMTUDISC_DO)
		skb->local_df = 1;

	*final_dst = fl6->daddr;
	__skb_pull(skb, skb_network_header_len(skb));
	if (opt && opt->opt_flen)
		ipv6_push_frag_opts(skb, opt, &proto);
	if (opt && opt->opt_nflen)
		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);

	skb_push(skb, sizeof(struct ipv6hdr));
	skb_reset_network_header(skb);
	hdr = ipv6_hdr(skb);

	ip6_flow_hdr(hdr, np->cork.tclass, fl6->flowlabel);
	hdr->hop_limit = np->cork.hop_limit;
	hdr->nexthdr = proto;
	hdr->saddr = fl6->saddr;
	hdr->daddr = *final_dst;

	skb->priority = sk->sk_priority;
	skb->mark = sk->sk_mark;

	skb_dst_set(skb, dst_clone(&rt->dst));
	IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
	if (proto == IPPROTO_ICMPV6) {
		struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));

		ICMP6MSGOUT_INC_STATS_BH(net, idev, icmp6_hdr(skb)->icmp6_type);
		ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
	}

	err = ip6_local_out(skb);
	if (err) {
		if (err > 0)
			err = net_xmit_errno(err);
		if (err)
			goto error;
	}

out:
	ip6_cork_release(inet, np);
	return err;
error:
	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
	goto out;
}


static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
{
	struct scsi_disk *sdkp;

	mutex_lock(&sd_ref_mutex);
	sdkp = __scsi_disk_get(disk);
	mutex_unlock(&sd_ref_mutex);
	return sdkp;
}


static int sd_open(struct block_device *bdev, fmode_t mode)
{
	struct scsi_disk *sdkp = scsi_disk_get(bdev->bd_disk);
	struct scsi_device *sdev;
	int retval;

	if (!sdkp)
		return -ENXIO;

	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n"));

	sdev = sdkp->device;

	retval = scsi_autopm_get_device(sdev);
	if (retval)
		goto error_autopm;

	/*
	 * If the device is in error recovery, wait until it is done.
	 * If the device is offline, then disallow any access to it.
	 */
	retval = -ENXIO;
	if (!scsi_block_when_processing_errors(sdev))
		goto error_out;

	if (sdev->removable || sdkp->write_prot)
		check_disk_change(bdev);

	/*
	 * If the drive is empty, just let the open fail.
	 */
	retval = -ENOMEDIUM;
	if (sdev->removable && !sdkp->media_present && !(mode & FMODE_NDELAY))
		goto error_out;

	/*
	 * If the device has the write protect tab set, have the open fail
	 * if the user expects to be able to write to the thing.
	 */
	retval = -EROFS;
	if (sdkp->write_prot && (mode & FMODE_WRITE))
		goto error_out;

	/*
	 * It is possible that the disk changing stuff resulted in
	 * the device being taken offline.  If this is the case,
	 * report this to the user, and don't pretend that the
	 * open actually succeeded.
	 */
	retval = -ENXIO;
	if (!scsi_device_online(sdev))
		goto error_out;

	if ((atomic_inc_return(&sdkp->openers) == 1) && sdev->removable) {
		if (scsi_block_when_processing_errors(sdev))
			scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
	}

	return 0;

error_out:
	scsi_autopm_put_device(sdev);
error_autopm:
	scsi_disk_put(sdkp);
	return retval;
}


static int sd_prep_fn(struct request_queue *q, struct request *rq)
{
	struct scsi_cmnd *SCpnt;
	struct scsi_device *sdp = q->queuedata;
	struct gendisk *disk = rq->rq_disk;
	struct scsi_disk *sdkp;
	sector_t block = blk_rq_pos(rq);
	sector_t threshold;
	unsigned int this_count = blk_rq_sectors(rq);
	int ret, host_dif;
	unsigned char protect;

	/*
	 * Discard request come in as REQ_TYPE_FS but we turn them into
	 * block PC requests to make life easier.
	 */
	if (rq->cmd_flags & REQ_DISCARD) {
		ret = scsi_setup_discard_cmnd(sdp, rq);
		goto out;
	} else if (rq->cmd_flags & REQ_FLUSH) {
		ret = scsi_setup_flush_cmnd(sdp, rq);
		goto out;
	} else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
		ret = scsi_setup_blk_pc_cmnd(sdp, rq);
		goto out;
	} else if (rq->cmd_type != REQ_TYPE_FS) {
		ret = BLKPREP_KILL;
		goto out;
	}
	ret = scsi_setup_fs_cmnd(sdp, rq);
	if (ret != BLKPREP_OK)
		goto out;
	SCpnt = rq->special;
	sdkp = scsi_disk(disk);

	/* from here on until we're complete, any goto out
	 * is used for a killable error condition */
	ret = BLKPREP_KILL;

	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
					"sd_init_command: block=%llu, "
					"count=%d\n",
					(unsigned long long)block,
					this_count));

	if (!sdp || !scsi_device_online(sdp) ||
	    block + blk_rq_sectors(rq) > get_capacity(disk)) {
		SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
						"Finishing %u sectors\n",
						blk_rq_sectors(rq)));
		SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
						"Retry with 0x%p\n", SCpnt));
		goto out;
	}

	if (sdp->changed) {
		/*
		 * quietly refuse to do anything to a changed disc until
		 * the changed bit has been reset
		 */
		/* printk("SCSI disk has been changed or is not present. Prohibiting further I/O.\n"); */
		goto out;
	}

	/*
	 * Some SD card readers can't handle multi-sector accesses which touch
	 * the last one or two hardware sectors.  Split accesses as needed.
	 */
	threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS *
		(sdp->sector_size / 512);

	if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) {
		if (block < threshold) {
			/* Access up to the threshold but not beyond */
			this_count = threshold - block;
		} else {
			/* Access only a single hardware sector */
			this_count = sdp->sector_size / 512;
		}
	}

	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
					(unsigned long long)block));

	/*
	 * If we have a 1K hardware sectorsize, prevent access to single
	 * 512 byte sectors.  In theory we could handle this - in fact
	 * the scsi cdrom driver must be able to handle this because
	 * we typically use 1K blocksizes, and cdroms typically have
	 * 2K hardware sectorsizes.  Of course, things are simpler
	 * with the cdrom, since it is read-only.  For performance
	 * reasons, the filesystems should be able to handle this
	 * and not force the scsi disk driver to use bounce buffers
	 * for this.
	 */
	if (sdp->sector_size == 1024) {
		if ((block & 1) || (blk_rq_sectors(rq) & 1)) {
			scmd_printk(KERN_ERR, SCpnt,
				    "Bad block number requested\n");
			goto out;
		} else {
			block = block >> 1;
			this_count = this_count >> 1;
		}
	}
	if (sdp->sector_size == 2048) {
		if ((block & 3) || (blk_rq_sectors(rq) & 3)) {
			scmd_printk(KERN_ERR, SCpnt,
				    "Bad block number requested\n");
			goto out;
		} else {
			block = block >> 2;
			this_count = this_count >> 2;
		}
	}
	if (sdp->sector_size == 4096) {
		if ((block & 7) || (blk_rq_sectors(rq) & 7)) {
			scmd_printk(KERN_ERR, SCpnt,
				    "Bad block number requested\n");
			goto out;
		} else {
			block = block >> 3;
			this_count = this_count >> 3;
		}
	}
	if (rq_data_dir(rq) == WRITE) {
		if (!sdp->writeable) {
			goto out;
		}
		SCpnt->cmnd[0] = WRITE_6;
		SCpnt->sc_data_direction = DMA_TO_DEVICE;

		if (blk_integrity_rq(rq) &&
		    sd_dif_prepare(rq, block, sdp->sector_size) == -EIO)
			goto out;

	} else if (rq_data_dir(rq) == READ) {
		SCpnt->cmnd[0] = READ_6;
		SCpnt->sc_data_direction = DMA_FROM_DEVICE;
	} else {
		scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
		goto out;
	}

	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
					"%s %d/%u 512 byte blocks.\n",
					(rq_data_dir(rq) == WRITE) ?
					"writing" : "reading", this_count,
					blk_rq_sectors(rq)));

	/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
	host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
	if (host_dif)
		protect = 1 << 5;
	else
		protect = 0;

	if (host_dif == SD_DIF_TYPE2_PROTECTION) {
		SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);

		if (unlikely(SCpnt->cmnd == NULL)) {
			ret = BLKPREP_DEFER;
			goto out;
		}

		SCpnt->cmd_len = SD_EXT_CDB_SIZE;
		memset(SCpnt->cmnd, 0, SCpnt->cmd_len);
		SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD;
		SCpnt->cmnd[7] = 0x18;
		SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32;
		SCpnt->cmnd[10] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0);

		/* LBA */
		SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
		SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
		SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
		SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0;
		SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff;
		SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff;
		SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff;
		SCpnt->cmnd[19] = (unsigned char) block & 0xff;

		/* Expected Indirect LBA */
		SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff;
		SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff;
		SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff;
		SCpnt->cmnd[23] = (unsigned char) block & 0xff;

		/* Transfer length */
		SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff;
		SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff;
		SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff;
		SCpnt->cmnd[31] = (unsigned char) this_count & 0xff;
	} else if (block > 0xffffffff) {
		SCpnt->cmnd[0] += READ_16 - READ_6;
		SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0);
		SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
		SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
		SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
		SCpnt->cmnd[5] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0;
		SCpnt->cmnd[6] = (unsigned char) (block >> 24) & 0xff;
		SCpnt->cmnd[7] = (unsigned char) (block >> 16) & 0xff;
		SCpnt->cmnd[8] = (unsigned char) (block >> 8) & 0xff;
		SCpnt->cmnd[9] = (unsigned char) block & 0xff;
		SCpnt->cmnd[10] = (unsigned char) (this_count >> 24) & 0xff;
		SCpnt->cmnd[11] = (unsigned char) (this_count >> 16) & 0xff;
		SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff;
		SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;
		SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;
	} else if ((this_count > 0xff) || (block > 0x1fffff) ||
		   scsi_device_protection(SCpnt->device) ||
		   SCpnt->device->use_10_for_rw) {
		if (this_count > 0xffff)
			this_count = 0xffff;

		SCpnt->cmnd[0] += READ_10 - READ_6;
		SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0);
		SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
		SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
		SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
		SCpnt->cmnd[5] = (unsigned char) block & 0xff;
		SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;
		SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
		SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
	} else {
		if (unlikely(rq->cmd_flags & REQ_FUA)) {
			/*
			 * This happens only if this drive failed
			 * 10byte rw command with ILLEGAL_REQUEST
			 * during operation and thus turned off
			 * use_10_for_rw.
			 */
			scmd_printk(KERN_ERR, SCpnt,
				    "FUA write on READ/WRITE(6) drive\n");
			goto out;
		}

		SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
		SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);
		SCpnt->cmnd[3] = (unsigned char) block & 0xff;
		SCpnt->cmnd[4] = (unsigned char) this_count;
		SCpnt->cmnd[5] = 0;
	}
	SCpnt->sdb.length = this_count * sdp->sector_size;

	/* If DIF or DIX is enabled, tell HBA how to handle request */
	if (host_dif || scsi_prot_sg_count(SCpnt))
		sd_prot_op(SCpnt, host_dif);

	/*
	 * We shouldn't disconnect in the middle of a sector, so with a dumb
	 * host adapter, it's safe to assume that we can at least transfer
	 * this many bytes between each connect / disconnect.
	 */
	SCpnt->transfersize = sdp->sector_size;
	SCpnt->underflow = this_count << 9;
	SCpnt->allowed = SD_MAX_RETRIES;

	/*
	 * This indicates that the command is ready from our end to be
	 * queued.
	 */
	ret = BLKPREP_OK;
 out:
	return scsi_prep_return(q, rq, ret);
}


sd_show_app_tag_own(struct device *dev, struct device_attribute *attr,
		    char *buf)
{
	struct scsi_disk *sdkp = to_scsi_disk(dev);

	return snprintf(buf, 20, "%u\n", sdkp->ATO);
}


static void sco_conn_del(struct hci_conn *hcon, int err)
{
	struct sco_conn *conn = hcon->sco_data;
	struct sock *sk;

	if (!conn)
		return;

	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);

	/* Kill socket */
	sco_conn_lock(conn);
	sk = conn->sk;
	sco_conn_unlock(conn);

	if (sk) {
		sock_hold(sk);
		lock_sock(sk);
		sco_sock_clear_timer(sk);
		sco_chan_del(sk, err);
		release_sock(sk);
		sock_put(sk);

		/* Ensure no more work items will run before freeing conn. */
		cancel_delayed_work_sync(&conn->timeout_work);
	}

	hcon->sco_data = NULL;
	kfree(conn);
}


bool ForwardCompatibilityWindowPassed(const VersionDef& versions) {
  // TF_GRAPH_DEF_VERSION is incremented daily.
  // TF has a 3 week forward compatibility guarantee.
  return (versions.producer() - TF_GRAPH_DEF_VERSION) > 21;
}


explicit NodeInfo(int i) : gdef_index(i), node(nullptr) {}


  Status TryImport() {
    TF_RETURN_IF_ERROR(EnsureNoNameCollisions());
    TF_RETURN_IF_ERROR(ValidateInputMapAndControlDependencies());
    TF_RETURN_IF_ERROR(BuildNodeIndex());
    TF_RETURN_IF_ERROR(InitFromEdges());

    // NOTE: Convert() invokes `consume_node_def()` on each node in the input
    // graph, so `get_node_def()` is no longer usable once it is called.
    TF_RETURN_IF_ERROR(Convert());

    TF_RETURN_IF_ERROR(AddBackEdges());
    TF_RETURN_IF_ERROR(UpdateVersionDef());
    TF_RETURN_IF_ERROR(PopulateReturnTensors());
    TF_RETURN_IF_ERROR(PopulateReturnNodes());
    TF_RETURN_IF_ERROR(PopulateMissingUnusedInputMapKeys());
    UpdateUniquifiedColocationNames();
    FixupSourceAndSinkEdges(g_);
    return Status::OK();
  }


Status GraphConstructor::IsNodeFullyMapped(const NodeDef& node_def,
                                           bool* is_node_mapped) {
  const OpDef* op_def;
  TF_RETURN_IF_ERROR(g_->op_registry()->LookUpOpDef(node_def.op(), &op_def));
  for (int i = 0; i < op_def->output_arg_size(); ++i) {
    if (opts_.input_map.find({node_def.name(), i}) == opts_.input_map.end()) {
      *is_node_mapped = false;
      return Status::OK();
    }
  }
  *is_node_mapped = true;
  return Status::OK();
}


    explicit InputInfo(const string& node_name, Node* n, int i)
        : name(node_name), node(n), index(i) {}


GF_Err tfxd_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_MSSTimeExtBox *ptr = (GF_MSSTimeExtBox*)s;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;

	gf_bs_write_u8(bs, ptr->version);
	gf_bs_write_u24(bs, 0);
	if (ptr->version) {
		gf_bs_write_u64(bs, ptr->absolute_time_in_track_timescale);
		gf_bs_write_u64(bs, ptr->fragment_duration_in_track_timescale);
	} else {
		gf_bs_write_u32(bs, (u32) ptr->absolute_time_in_track_timescale);
		gf_bs_write_u32(bs, (u32) ptr->fragment_duration_in_track_timescale);
	}
	return GF_OK;
}


GF_Err mhap_box_read(GF_Box *s,GF_BitStream *bs)
{
	u32 i;
	GF_MHACompatibleProfilesBox *ptr = (GF_MHACompatibleProfilesBox *) s;

	ISOM_DECREASE_SIZE(s, 1)
	ptr->num_profiles = gf_bs_read_u8(bs);
	if (!ptr->num_profiles) return GF_OK;

	ISOM_DECREASE_SIZE(s, ptr->num_profiles)
	ptr->compat_profiles = gf_malloc(sizeof(u8) * ptr->num_profiles);
	if (!ptr->compat_profiles) return GF_OUT_OF_MEM;
	for (i=0; i<ptr->num_profiles; i++) {
		ptr->compat_profiles[i] = gf_bs_read_u8(bs);
	}
	return GF_OK;


GF_Err xtra_box_size(GF_Box *s)
{
	GF_XtraBox *ptr = (GF_XtraBox *)s;
	u32 i, count = gf_list_count(ptr->tags);
	for (i=0; i<count; i++) {
		GF_XtraTag *tag = gf_list_get(ptr->tags, i);
		ptr->size += 18 + (u32) strlen(tag->name) + tag->prop_size;
	}
	return GF_OK;


GF_Err mhap_box_write(GF_Box *s, GF_BitStream *bs)
{
	u32 i;
	GF_Err e;
	GF_MHACompatibleProfilesBox *ptr = (GF_MHACompatibleProfilesBox *) s;

	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u8(bs, ptr->num_profiles);
	for (i=0; i<ptr->num_profiles; i++) {
		gf_bs_write_u8(bs, ptr->compat_profiles[i]);
	}
	return GF_OK;


GF_Err proj_type_box_size(GF_Box *s)
{
	GF_ProjectionTypeBox *ptr = (GF_ProjectionTypeBox *)s;
	if (ptr->type==GF_ISOM_BOX_TYPE_CBMP)
		s->size += 8;
	else if (ptr->type==GF_ISOM_BOX_TYPE_EQUI)
		s->size += 16;
	else
		s->size += 8;

	return GF_OK;


}
GF_Err csgp_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i, bits, gidx_mask;
	Bool index_msb_indicates_fragment_local_description, grouping_type_parameter_present;
	u32 pattern_size, scount_size, index_size;
	GF_CompactSampleGroupBox *ptr = (GF_CompactSampleGroupBox *)s;

	ISOM_DECREASE_SIZE(ptr, 8);
	ptr->version = gf_bs_read_u8(bs);
	ptr->flags = gf_bs_read_u24(bs);

	index_msb_indicates_fragment_local_description = (ptr->flags & (1<<7)) ? GF_TRUE : GF_FALSE;
	grouping_type_parameter_present = (ptr->flags & (1<<6)) ? GF_TRUE : GF_FALSE;

	pattern_size = get_size_by_code( ((ptr->flags>>4) & 0x3) );
	scount_size = get_size_by_code( ((ptr->flags>>2) & 0x3) );
	index_size = get_size_by_code( (ptr->flags & 0x3) );

	if (((pattern_size==4) && (scount_size!=4)) || ((pattern_size!=4) && (scount_size==4))) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] compact sample gorup pattern_size and sample_count_size mare not both 4 bits\n"));
		return GF_ISOM_INVALID_FILE;
	}

	ptr->grouping_type = gf_bs_read_u32(bs);
	if (grouping_type_parameter_present) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->grouping_type_parameter = gf_bs_read_u32(bs);
	}
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->pattern_count = gf_bs_read_u32(bs);

	if (ptr->size < ptr->pattern_count * (pattern_size + scount_size) / 8 )
	    return GF_ISOM_INVALID_FILE;

	ptr->patterns = gf_malloc(sizeof(GF_CompactSampleGroupPattern) * ptr->pattern_count);
	if (!ptr->patterns) return GF_OUT_OF_MEM;

	bits = 0;
	for (i=0; i<ptr->pattern_count; i++) {
		ptr->patterns[i].length = gf_bs_read_int(bs, pattern_size);
		ptr->patterns[i].sample_count = gf_bs_read_int(bs, scount_size);
		bits += pattern_size + scount_size;
		if (! (bits % 8)) {
			bits/=8;
			ISOM_DECREASE_SIZE(ptr, bits);
			bits=0;
		}
		ptr->patterns[i].sample_group_description_indices = gf_malloc(sizeof(u32) * ptr->patterns[i].length);
		if (!ptr->patterns[i].sample_group_description_indices) return GF_OUT_OF_MEM;
	}
	bits = 0;
	gidx_mask = ((u32)1) << (index_size-1);
	for (i=0; i<ptr->pattern_count; i++) {
		u32 j;
		for (j=0; j<ptr->patterns[i].length; j++) {
			u32 idx = gf_bs_read_int(bs, index_size);
			if (index_msb_indicates_fragment_local_description) {
				//MSB set, this is a index of a group described in the fragment
				if (idx & gidx_mask) {
					idx += 0x10000;
				}
			}
			ptr->patterns[i].sample_group_description_indices[j] = idx;
			bits += index_size;

			if (! (bits % 8)) {
				bits/=8;
				ISOM_DECREASE_SIZE(ptr, bits);
				bits=0;
			}
		}
	}
	if (bits)
		gf_bs_align(bs);
	return GF_OK;


GF_Err prhd_box_size(GF_Box *s)
{
	s->size += 12;
	return GF_OK;


GF_Err mfra_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_MovieFragmentRandomAccessBox *ptr = (GF_MovieFragmentRandomAccessBox *)s;
	switch(a->type) {
	case GF_ISOM_BOX_TYPE_TFRA:
		BOX_FIELD_LIST_ASSIGN(tfra_list);
		return GF_OK;
	case GF_ISOM_BOX_TYPE_MFRO:
		BOX_FIELD_ASSIGN(mfro, GF_MovieFragmentRandomAccessOffsetBox)
		return GF_OK;
	}
	return GF_OK;
}


GF_Err mvex_box_read(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_array_read(s, bs);
}


GF_Err strk_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_SubTrackBox *ptr = (GF_SubTrackBox *)s;
	if (!a) return GF_OK;
	switch (a->type) {
	case GF_ISOM_BOX_TYPE_STRI:
		BOX_FIELD_ASSIGN(info, GF_SubTrackInformationBox)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_STRD:
		BOX_FIELD_ASSIGN(strd, GF_Box)
		return GF_OK;
	}
	return GF_OK;


GF_Err dmlp_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TrueHDConfigBox *ptr = (GF_TrueHDConfigBox *)s;
	ISOM_DECREASE_SIZE(ptr, 10)
	ptr->format_info = gf_bs_read_u32(bs);
	ptr->peak_data_rate = gf_bs_read_int(bs, 15);
	gf_bs_read_int(bs, 1);
	gf_bs_read_u32(bs);
	return GF_OK;


GF_Err proj_type_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_ProjectionTypeBox *ptr = (GF_ProjectionTypeBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	if (ptr->type==GF_ISOM_BOX_TYPE_CBMP) {
		gf_bs_write_u32(bs, ptr->layout);
		gf_bs_write_u32(bs, ptr->padding);
	}
	else if (ptr->type==GF_ISOM_BOX_TYPE_EQUI) {
		gf_bs_write_u32(bs, ptr->bounds_top);
		gf_bs_write_u32(bs, ptr->bounds_bottom);
		gf_bs_write_u32(bs, ptr->bounds_left);
		gf_bs_write_u32(bs, ptr->bounds_right);
	} else {
		gf_bs_write_u32(bs, ptr->crc);
		gf_bs_write_u32(bs, ptr->encoding_4cc);
	}
	return GF_OK;


MONGO_EXPORT time_t bson_iterator_time_t( const bson_iterator *i ) {
    return bson_iterator_date( i ) / 1000;
}


MONGO_EXPORT void bson_iterator_subobject( const bson_iterator *i, bson *sub ) {
    bson_init_data( sub, ( char * )bson_iterator_value( i ) );
    _bson_reset( sub );
    sub->finished = 1;
}


MONGO_EXPORT int bson_iterator_int( const bson_iterator *i ) {
    switch ( bson_iterator_type( i ) ) {
    case BSON_INT:
        return bson_iterator_int_raw( i );
    case BSON_LONG:
        return ( int )bson_iterator_long_raw( i );
    case BSON_DOUBLE:
        return bson_iterator_double_raw( i );
    default:
        return 0;
    }
}


static int isLegalUTF8( const unsigned char *source, int length ) {
    unsigned char a;
    const unsigned char *srcptr = source + length;
    switch ( length ) {
    default:
        return 0;
        /* Everything else falls through when "true"... */
    case 4:
        if ( ( a = ( *--srcptr ) ) < 0x80 || a > 0xBF ) return 0;
    case 3:
        if ( ( a = ( *--srcptr ) ) < 0x80 || a > 0xBF ) return 0;
    case 2:
        if ( ( a = ( *--srcptr ) ) > 0xBF ) return 0;
        switch ( *source ) {
            /* no fall-through in this inner switch */
        case 0xE0:
            if ( a < 0xA0 ) return 0;
            break;
        case 0xF0:
            if ( a < 0x90 ) return 0;
            break;
        case 0xF4:
            if ( a > 0x8F ) return 0;
            break;
        default:
            if ( a < 0x80 ) return 0;
        }
    case 1:
        if ( *source >= 0x80 && *source < 0xC2 ) return 0;
        if ( *source > 0xF4 ) return 0;
    }
    return 1;
}


MONGO_EXPORT const char *bson_data( const bson *b ) {
    return (const char *)b->data;
}


MONGO_EXPORT int bson_append_date( bson *b, const char *name, bson_date_t millis ) {
    if ( bson_append_estart( b, BSON_DATE, name, 8 ) == BSON_ERROR ) return BSON_ERROR;
    bson_append64( b , &millis );
    return BSON_OK;
}


int gridfs_find_filename( gridfs *gfs, const char *filename,
                          gridfile *gfile )

{
    bson query;
    int i;

    bson_init( &query );
    bson_append_string( &query, "filename", filename );
    bson_finish( &query );
    i = gridfs_find_query( gfs, &query, gfile );
    bson_destroy( &query );
    return i;
}


MONGO_EXPORT void mongo_clear_errors( mongo *conn ) {
    conn->err = 0;
    conn->errcode = 0;
    conn->lasterrcode = 0;
    memset( conn->errstr, 0, MONGO_ERR_LEN );
    memset( conn->lasterrstr, 0, MONGO_ERR_LEN );
}


int mongo_env_read_socket( mongo *conn, void *buf, size_t len ) {
    char *cbuf = buf;

    while ( len ) {
        size_t sent = recv( conn->sock, cbuf, len, 0 );
        if ( sent == 0 || sent == -1 ) {
            __mongo_set_error( conn, MONGO_IO_ERROR, NULL, WSAGetLastError() );
            return MONGO_ERROR;
        }
        cbuf += sent;
        len -= sent;
    }

    return MONGO_OK;
}


static char *mongo_ns_to_cmd_db( const char *ns ) {
    char *current = NULL;
    char *cmd_db_name = NULL;
    int len = 0;

    for( current = (char *)ns; *current != '.'; current++ ) {
        len++;
    }

    cmd_db_name = (char *)bson_malloc( len + 6 );
    strncpy( cmd_db_name, ns, len );
    strncpy( cmd_db_name + len, ".$cmd", 6 );

    return cmd_db_name;
}


MONGO_EXPORT const char* mongo_get_primary(mongo* conn) {
    mongo* conn_ = (mongo*)conn;
    if( !(conn_->connected) || (conn_->primary->host[0] == '\0') )
        return NULL;
    return _get_host_port(conn_->primary);
}


MONGO_EXPORT int bson_size( const bson *b ) {
    int i;
    if ( ! b || ! b->data )
        return 0;
    bson_little_endian32( &i, b->data );
    return i;
}


static int gridfs_insert_file( gridfs *gfs, const char *name,
                               const bson_oid_t id, gridfs_offset length,
                               const char *contenttype ) {
    bson command;
    bson ret;
    bson res;
    bson_iterator it;
    int result;
    int64_t d;

    /* Check run md5 */
    bson_init( &command );
    bson_append_oid( &command, "filemd5", &id );
    bson_append_string( &command, "root", gfs->prefix );
    bson_finish( &command );
    result = mongo_run_command( gfs->client, gfs->dbname, &command, &res );
    bson_destroy( &command );
    if (result != MONGO_OK)
        return result;

    /* Create and insert BSON for file metadata */
    bson_init( &ret );
    bson_append_oid( &ret, "_id", &id );
    if ( name != NULL && *name != '\0' ) {
        bson_append_string( &ret, "filename", name );
    }
    bson_append_long( &ret, "length", length );
    bson_append_int( &ret, "chunkSize", DEFAULT_CHUNK_SIZE );
    d = ( bson_date_t )1000*time( NULL );
    bson_append_date( &ret, "uploadDate", d);
    bson_find( &it, &res, "md5" );
    bson_append_string( &ret, "md5", bson_iterator_string( &it ) );
    bson_destroy( &res );
    if ( contenttype != NULL && *contenttype != '\0' ) {
        bson_append_string( &ret, "contentType", contenttype );
    }
    bson_finish( &ret );
    result = mongo_insert( gfs->client, gfs->files_ns, &ret, NULL );
    bson_destroy( &ret );

    return result;
}