예제 #1
0
void rxrpc_process_connection(struct work_struct *work)
{
	struct rxrpc_connection *conn =
		container_of(work, struct rxrpc_connection, processor);
	struct rxrpc_skb_priv *sp;
	struct sk_buff *skb;
	u32 abort_code = RX_PROTOCOL_ERROR;
	int ret;

	_enter("{%d}", conn->debug_id);

	atomic_inc(&conn->usage);

	if (test_and_clear_bit(RXRPC_CONN_CHALLENGE, &conn->events)) {
		rxrpc_secure_connection(conn);
		rxrpc_put_connection(conn);
	}

	/* go through the conn-level event packets, releasing the ref on this
	 * connection that each one has when we've finished with it */
	while ((skb = skb_dequeue(&conn->rx_queue))) {
		sp = rxrpc_skb(skb);

		ret = rxrpc_process_event(conn, skb, &abort_code);
		switch (ret) {
		case -EPROTO:
		case -EKEYEXPIRED:
		case -EKEYREJECTED:
			goto protocol_error;
		case -EAGAIN:
			goto requeue_and_leave;
		case -ECONNABORTED:
		default:
			rxrpc_put_connection(conn);
			rxrpc_free_skb(skb);
			break;
		}
	}

out:
	rxrpc_put_connection(conn);
	_leave("");
	return;

requeue_and_leave:
	skb_queue_head(&conn->rx_queue, skb);
	goto out;

protocol_error:
	if (rxrpc_abort_connection(conn, -ret, abort_code) < 0)
		goto requeue_and_leave;
	rxrpc_put_connection(conn);
	rxrpc_free_skb(skb);
	_leave(" [EPROTO]");
	goto out;
}
예제 #2
0
파일: conn_event.c 프로젝트: guribe94/linux
/*
 * connection-level event processor
 */
void rxrpc_process_connection(struct work_struct *work)
{
	struct rxrpc_connection *conn =
		container_of(work, struct rxrpc_connection, processor);
	struct sk_buff *skb;
	u32 abort_code = RX_PROTOCOL_ERROR;
	int ret;

	rxrpc_see_connection(conn);

	if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
		rxrpc_secure_connection(conn);

	/* Process delayed ACKs whose time has come. */
	if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK)
		rxrpc_process_delayed_final_acks(conn);

	/* go through the conn-level event packets, releasing the ref on this
	 * connection that each one has when we've finished with it */
	while ((skb = skb_dequeue(&conn->rx_queue))) {
		rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
		ret = rxrpc_process_event(conn, skb, &abort_code);
		switch (ret) {
		case -EPROTO:
		case -EKEYEXPIRED:
		case -EKEYREJECTED:
			goto protocol_error;
		case -ENOMEM:
		case -EAGAIN:
			goto requeue_and_leave;
		case -ECONNABORTED:
		default:
			rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
			break;
		}
	}

out:
	rxrpc_put_connection(conn);
	_leave("");
	return;

requeue_and_leave:
	skb_queue_head(&conn->rx_queue, skb);
	goto out;

protocol_error:
	if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
		goto requeue_and_leave;
	rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
	goto out;
}
예제 #3
0
파일: output.c 프로젝트: AshishNamdev/linux
/*
 * Send an ABORT call packet.
 */
int rxrpc_send_abort_packet(struct rxrpc_call *call)
{
	struct rxrpc_connection *conn = NULL;
	struct rxrpc_abort_buffer pkt;
	struct msghdr msg;
	struct kvec iov[1];
	rxrpc_serial_t serial;
	int ret;

	spin_lock_bh(&call->lock);
	if (call->conn)
		conn = rxrpc_get_connection_maybe(call->conn);
	spin_unlock_bh(&call->lock);
	if (!conn)
		return -ECONNRESET;

	msg.msg_name	= &call->peer->srx.transport;
	msg.msg_namelen	= call->peer->srx.transport_len;
	msg.msg_control	= NULL;
	msg.msg_controllen = 0;
	msg.msg_flags	= 0;

	pkt.whdr.epoch		= htonl(conn->proto.epoch);
	pkt.whdr.cid		= htonl(call->cid);
	pkt.whdr.callNumber	= htonl(call->call_id);
	pkt.whdr.seq		= 0;
	pkt.whdr.type		= RXRPC_PACKET_TYPE_ABORT;
	pkt.whdr.flags		= conn->out_clientflag;
	pkt.whdr.userStatus	= 0;
	pkt.whdr.securityIndex	= call->security_ix;
	pkt.whdr._rsvd		= 0;
	pkt.whdr.serviceId	= htons(call->service_id);
	pkt.abort_code		= htonl(call->abort_code);

	iov[0].iov_base	= &pkt;
	iov[0].iov_len	= sizeof(pkt);

	serial = atomic_inc_return(&conn->serial);
	pkt.whdr.serial = htonl(serial);

	ret = kernel_sendmsg(conn->params.local->socket,
			     &msg, iov, 1, sizeof(pkt));

	rxrpc_put_connection(conn);
	return ret;
}
예제 #4
0
파일: call_accept.c 프로젝트: gxt/linux
/*
 * accept an incoming call that needs peer, transport and/or connection setting
 * up
 */
static int rxrpc_accept_incoming_call(struct rxrpc_local *local,
				      struct rxrpc_sock *rx,
				      struct sk_buff *skb,
				      struct sockaddr_rxrpc *srx)
{
	struct rxrpc_connection *conn;
	struct rxrpc_skb_priv *sp, *nsp;
	struct rxrpc_call *call;
	struct sk_buff *notification;
	int ret;

	_enter("");

	sp = rxrpc_skb(skb);

	/* get a notification message to send to the server app */
	notification = alloc_skb(0, GFP_NOFS);
	if (!notification) {
		_debug("no memory");
		ret = -ENOMEM;
		goto error_nofree;
	}
	rxrpc_new_skb(notification);
	notification->mark = RXRPC_SKB_MARK_NEW_CALL;

	conn = rxrpc_incoming_connection(local, srx, skb);
	if (IS_ERR(conn)) {
		_debug("no conn");
		ret = PTR_ERR(conn);
		goto error;
	}

	call = rxrpc_incoming_call(rx, conn, skb);
	rxrpc_put_connection(conn);
	if (IS_ERR(call)) {
		_debug("no call");
		ret = PTR_ERR(call);
		goto error;
	}

	/* attach the call to the socket */
	read_lock_bh(&local->services_lock);
	if (rx->sk.sk_state == RXRPC_CLOSE)
		goto invalid_service;

	write_lock(&rx->call_lock);
	if (!test_and_set_bit(RXRPC_CALL_INIT_ACCEPT, &call->flags)) {
		rxrpc_get_call(call);

		spin_lock(&call->conn->state_lock);
		if (sp->hdr.securityIndex > 0 &&
		    call->conn->state == RXRPC_CONN_SERVICE_UNSECURED) {
			_debug("await conn sec");
			list_add_tail(&call->accept_link, &rx->secureq);
			call->conn->state = RXRPC_CONN_SERVICE_CHALLENGING;
			set_bit(RXRPC_CONN_EV_CHALLENGE, &call->conn->events);
			rxrpc_queue_conn(call->conn);
		} else {
			_debug("conn ready");
			call->state = RXRPC_CALL_SERVER_ACCEPTING;
			list_add_tail(&call->accept_link, &rx->acceptq);
			rxrpc_get_call(call);
			atomic_inc(&call->skb_count);
			nsp = rxrpc_skb(notification);
			nsp->call = call;

			ASSERTCMP(atomic_read(&call->usage), >=, 3);

			_debug("notify");
			spin_lock(&call->lock);
			ret = rxrpc_queue_rcv_skb(call, notification, true,
						  false);
			spin_unlock(&call->lock);
			notification = NULL;
			BUG_ON(ret < 0);
		}
		spin_unlock(&call->conn->state_lock);

		_debug("queued");
	}
예제 #5
0
파일: output.c 프로젝트: AshishNamdev/linux
/*
 * Send an ACK call packet.
 */
int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping)
{
	struct rxrpc_connection *conn = NULL;
	struct rxrpc_ack_buffer *pkt;
	struct msghdr msg;
	struct kvec iov[2];
	rxrpc_serial_t serial;
	rxrpc_seq_t hard_ack, top;
	size_t len, n;
	int ret;
	u8 reason;

	spin_lock_bh(&call->lock);
	if (call->conn)
		conn = rxrpc_get_connection_maybe(call->conn);
	spin_unlock_bh(&call->lock);
	if (!conn)
		return -ECONNRESET;

	pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
	if (!pkt) {
		rxrpc_put_connection(conn);
		return -ENOMEM;
	}

	msg.msg_name	= &call->peer->srx.transport;
	msg.msg_namelen	= call->peer->srx.transport_len;
	msg.msg_control	= NULL;
	msg.msg_controllen = 0;
	msg.msg_flags	= 0;

	pkt->whdr.epoch		= htonl(conn->proto.epoch);
	pkt->whdr.cid		= htonl(call->cid);
	pkt->whdr.callNumber	= htonl(call->call_id);
	pkt->whdr.seq		= 0;
	pkt->whdr.type		= RXRPC_PACKET_TYPE_ACK;
	pkt->whdr.flags		= RXRPC_SLOW_START_OK | conn->out_clientflag;
	pkt->whdr.userStatus	= 0;
	pkt->whdr.securityIndex	= call->security_ix;
	pkt->whdr._rsvd		= 0;
	pkt->whdr.serviceId	= htons(call->service_id);

	spin_lock_bh(&call->lock);
	if (ping) {
		reason = RXRPC_ACK_PING;
	} else {
		reason = call->ackr_reason;
		if (!call->ackr_reason) {
			spin_unlock_bh(&call->lock);
			ret = 0;
			goto out;
		}
		call->ackr_reason = 0;
	}
	n = rxrpc_fill_out_ack(call, pkt, &hard_ack, &top, reason);

	spin_unlock_bh(&call->lock);

	iov[0].iov_base	= pkt;
	iov[0].iov_len	= sizeof(pkt->whdr) + sizeof(pkt->ack) + n;
	iov[1].iov_base = &pkt->ackinfo;
	iov[1].iov_len	= sizeof(pkt->ackinfo);
	len = iov[0].iov_len + iov[1].iov_len;

	serial = atomic_inc_return(&conn->serial);
	pkt->whdr.serial = htonl(serial);
	trace_rxrpc_tx_ack(call, serial,
			   ntohl(pkt->ack.firstPacket),
			   ntohl(pkt->ack.serial),
			   pkt->ack.reason, pkt->ack.nAcks);

	if (ping) {
		call->ping_serial = serial;
		smp_wmb();
		/* We need to stick a time in before we send the packet in case
		 * the reply gets back before kernel_sendmsg() completes - but
		 * asking UDP to send the packet can take a relatively long
		 * time, so we update the time after, on the assumption that
		 * the packet transmission is more likely to happen towards the
		 * end of the kernel_sendmsg() call.
		 */
		call->ping_time = ktime_get_real();
		set_bit(RXRPC_CALL_PINGING, &call->flags);
		trace_rxrpc_rtt_tx(call, rxrpc_rtt_tx_ping, serial);
	}

	ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
	if (ping)
		call->ping_time = ktime_get_real();

	if (call->state < RXRPC_CALL_COMPLETE) {
		if (ret < 0) {
			if (ping)
				clear_bit(RXRPC_CALL_PINGING, &call->flags);
			rxrpc_propose_ACK(call, pkt->ack.reason,
					  ntohs(pkt->ack.maxSkew),
					  ntohl(pkt->ack.serial),
					  true, true,
					  rxrpc_propose_ack_retry_tx);
		} else {
			spin_lock_bh(&call->lock);
			if (after(hard_ack, call->ackr_consumed))
				call->ackr_consumed = hard_ack;
			if (after(top, call->ackr_seen))
				call->ackr_seen = top;
			spin_unlock_bh(&call->lock);
		}
	}

out:
	rxrpc_put_connection(conn);
	kfree(pkt);
	return ret;
}