static int vmci_transport_recv_listen(struct sock *sk,
				      struct vmci_transport_packet *pkt)
{
	struct sock *pending;
	struct vsock_sock *vpending;
	int err;
	u64 qp_size;
	bool old_request = false;
	bool old_pkt_proto = false;

	err = 0;

	/* Because we are in the listen state, we could be receiving a packet
	 * for ourself or any previous connection requests that we received.
	 * If it's the latter, we try to find a socket in our list of pending
	 * connections and, if we do, call the appropriate handler for the
	 * state that that socket is in.  Otherwise we try to service the
	 * connection request.
	 */
	pending = vmci_transport_get_pending(sk, pkt);
	if (pending) {
		lock_sock(pending);

		/* The local context ID may be out of date. */
		vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context;

		switch (pending->sk_state) {
		case SS_CONNECTING:
			err = vmci_transport_recv_connecting_server(sk,
								    pending,
								    pkt);
			break;
		default:
			vmci_transport_send_reset(pending, pkt);
			err = -EINVAL;
		}

		if (err < 0)
			vsock_remove_pending(sk, pending);

		release_sock(pending);
		vmci_transport_release_pending(pending);

		return err;
	}

	/* The listen state only accepts connection requests.  Reply with a
	 * reset unless we received a reset.
	 */

	if (!(pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST ||
	      pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST2)) {
		vmci_transport_reply_reset(pkt);
		return -EINVAL;
	}

	if (pkt->u.size == 0) {
		vmci_transport_reply_reset(pkt);
		return -EINVAL;
	}

	/* If this socket can't accommodate this connection request, we send a
	 * reset.  Otherwise we create and initialize a child socket and reply
	 * with a connection negotiation.
	 */
	if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) {
		vmci_transport_reply_reset(pkt);
		return -ECONNREFUSED;
	}

	pending = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL,
				 sk->sk_type);
	if (!pending) {
		vmci_transport_send_reset(sk, pkt);
		return -ENOMEM;
	}

	vpending = vsock_sk(pending);

	vsock_addr_init(&vpending->local_addr, pkt->dg.dst.context,
			pkt->dst_port);
	vsock_addr_init(&vpending->remote_addr, pkt->dg.src.context,
			pkt->src_port);

	/* If the proposed size fits within our min/max, accept it. Otherwise
	 * propose our own size.
	 */
	if (pkt->u.size >= vmci_trans(vpending)->queue_pair_min_size &&
	    pkt->u.size <= vmci_trans(vpending)->queue_pair_max_size) {
		qp_size = pkt->u.size;
	} else {
		qp_size = vmci_trans(vpending)->queue_pair_size;
	}

	/* Figure out if we are using old or new requests based on the
	 * overrides pkt types sent by our peer.
	 */
	if (vmci_transport_old_proto_override(&old_pkt_proto)) {
		old_request = old_pkt_proto;
	} else {
		if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST)
			old_request = true;
		else if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST2)
			old_request = false;

	}

	if (old_request) {
		/* Handle a REQUEST (or override) */
		u16 version = VSOCK_PROTO_INVALID;
		if (vmci_transport_proto_to_notify_struct(
			pending, &version, true))
			err = vmci_transport_send_negotiate(pending, qp_size);
		else
			err = -EINVAL;

	} else {
		/* Handle a REQUEST2 (or override) */
		int proto_int = pkt->proto;
		int pos;
		u16 active_proto_version = 0;

		/* The list of possible protocols is the intersection of all
		 * protocols the client supports ... plus all the protocols we
		 * support.
		 */
		proto_int &= vmci_transport_new_proto_supported_versions();

		/* We choose the highest possible protocol version and use that
		 * one.
		 */
		pos = fls(proto_int);
		if (pos) {
			active_proto_version = (1 << (pos - 1));
			if (vmci_transport_proto_to_notify_struct(
				pending, &active_proto_version, false))
				err = vmci_transport_send_negotiate2(pending,
							qp_size,
							active_proto_version);
			else
				err = -EINVAL;

		} else {
			err = -EINVAL;
		}
	}

	if (err < 0) {
		vmci_transport_send_reset(sk, pkt);
		sock_put(pending);
		err = vmci_transport_error_to_vsock_error(err);
		goto out;
	}

	vsock_add_pending(sk, pending);
	sk->sk_ack_backlog++;

	pending->sk_state = SS_CONNECTING;
	vmci_trans(vpending)->produce_size =
		vmci_trans(vpending)->consume_size = qp_size;
	vmci_trans(vpending)->queue_pair_size = qp_size;

	vmci_trans(vpending)->notify_ops->process_request(pending);

	/* We might never receive another message for this socket and it's not
	 * connected to any process, so we have to ensure it gets cleaned up
	 * ourself.  Our delayed work function will take care of that.  Note
	 * that we do not ever cancel this function since we have few
	 * guarantees about its state when calling cancel_delayed_work().
	 * Instead we hold a reference on the socket for that function and make
	 * it capable of handling cases where it needs to do nothing but
	 * release that reference.
	 */
	vpending->listener = sk;
	sock_hold(sk);
	sock_hold(pending);
	INIT_DELAYED_WORK(&vpending->dwork, vsock_pending_work);
	schedule_delayed_work(&vpending->dwork, HZ);

out:
	return err;
}
static int vmci_transport_recv_listen(struct sock *sk,
				      struct vmci_transport_packet *pkt)
{
	struct sock *pending;
	struct vsock_sock *vpending;
	int err;
	u64 qp_size;
	bool old_request = false;
	bool old_pkt_proto = false;

	err = 0;

	 
	pending = vmci_transport_get_pending(sk, pkt);
	if (pending) {
		lock_sock(pending);

		 
		vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context;

		switch (pending->sk_state) {
		case SS_CONNECTING:
			err = vmci_transport_recv_connecting_server(sk,
								    pending,
								    pkt);
			break;
		default:
			vmci_transport_send_reset(pending, pkt);
			err = -EINVAL;
		}

		if (err < 0)
			vsock_remove_pending(sk, pending);

		release_sock(pending);
		vmci_transport_release_pending(pending);

		return err;
	}

	 

	if (!(pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST ||
	      pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST2)) {
		vmci_transport_reply_reset(pkt);
		return -EINVAL;
	}

	if (pkt->u.size == 0) {
		vmci_transport_reply_reset(pkt);
		return -EINVAL;
	}

	 
	if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) {
		vmci_transport_reply_reset(pkt);
		return -ECONNREFUSED;
	}

	pending = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL,
				 sk->sk_type);
	if (!pending) {
		vmci_transport_send_reset(sk, pkt);
		return -ENOMEM;
	}

	vpending = vsock_sk(pending);

	vsock_addr_init(&vpending->local_addr, pkt->dg.dst.context,
			pkt->dst_port);
	vsock_addr_init(&vpending->remote_addr, pkt->dg.src.context,
			pkt->src_port);

	 
	if (pkt->u.size >= vmci_trans(vpending)->queue_pair_min_size &&
	    pkt->u.size <= vmci_trans(vpending)->queue_pair_max_size) {
		qp_size = pkt->u.size;
	} else {
		qp_size = vmci_trans(vpending)->queue_pair_size;
	}

	 
	if (vmci_transport_old_proto_override(&old_pkt_proto)) {
		old_request = old_pkt_proto;
	} else {
		if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST)
			old_request = true;
		else if (pkt->type == VMCI_TRANSPORT_PACKET_TYPE_REQUEST2)
			old_request = false;

	}

	if (old_request) {
		 
		u16 version = VSOCK_PROTO_INVALID;
		if (vmci_transport_proto_to_notify_struct(
			pending, &version, true))
			err = vmci_transport_send_negotiate(pending, qp_size);
		else
			err = -EINVAL;

	} else {
		 
		int proto_int = pkt->proto;
		int pos;
		u16 active_proto_version = 0;

		 
		proto_int &= vmci_transport_new_proto_supported_versions();

		 
		pos = fls(proto_int);
		if (pos) {
			active_proto_version = (1 << (pos - 1));
			if (vmci_transport_proto_to_notify_struct(
				pending, &active_proto_version, false))
				err = vmci_transport_send_negotiate2(pending,
							qp_size,
							active_proto_version);
			else
				err = -EINVAL;

		} else {
			err = -EINVAL;
		}
	}

	if (err < 0) {
		vmci_transport_send_reset(sk, pkt);
		sock_put(pending);
		err = vmci_transport_error_to_vsock_error(err);
		goto out;
	}

	vsock_add_pending(sk, pending);
	sk->sk_ack_backlog++;

	pending->sk_state = SS_CONNECTING;
	vmci_trans(vpending)->produce_size =
		vmci_trans(vpending)->consume_size = qp_size;
	vmci_trans(vpending)->queue_pair_size = qp_size;

	vmci_trans(vpending)->notify_ops->process_request(pending);

	 
	vpending->listener = sk;
	sock_hold(sk);
	sock_hold(pending);
	INIT_DELAYED_WORK(&vpending->dwork, vsock_pending_work);
	schedule_delayed_work(&vpending->dwork, HZ);

out:
	return err;
}