예제 #1
0
/*
 * Process event packets targetted at a local endpoint.
 */
void rxrpc_process_local_events(struct rxrpc_local *local)
{
	struct sk_buff *skb;
	char v;

	_enter("");

	skb = skb_dequeue(&local->event_queue);
	if (skb) {
		struct rxrpc_skb_priv *sp = rxrpc_skb(skb);

		rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
		_debug("{%d},{%u}", local->debug_id, sp->hdr.type);

		switch (sp->hdr.type) {
		case RXRPC_PACKET_TYPE_VERSION:
			if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
					  &v, 1) < 0)
				return;
			_proto("Rx VERSION { %02x }", v);
			if (v == 0)
				rxrpc_send_version_request(local, &sp->hdr, skb);
			break;

		default:
			/* Just ignore anything we don't understand */
			break;
		}

		rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
	}

	_leave("");
}
예제 #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
/*
 * reject packets through the local endpoint
 */
void rxrpc_reject_packets(struct rxrpc_local *local)
{
	struct sockaddr_rxrpc srx;
	struct rxrpc_skb_priv *sp;
	struct rxrpc_wire_header whdr;
	struct sk_buff *skb;
	struct msghdr msg;
	struct kvec iov[2];
	size_t size;
	__be32 code;

	_enter("%d", local->debug_id);

	iov[0].iov_base = &whdr;
	iov[0].iov_len = sizeof(whdr);
	iov[1].iov_base = &code;
	iov[1].iov_len = sizeof(code);
	size = sizeof(whdr) + sizeof(code);

	msg.msg_name = &srx.transport;
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	msg.msg_flags = 0;

	memset(&whdr, 0, sizeof(whdr));
	whdr.type = RXRPC_PACKET_TYPE_ABORT;

	while ((skb = skb_dequeue(&local->reject_queue))) {
		rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
		sp = rxrpc_skb(skb);

		if (rxrpc_extract_addr_from_skb(&srx, skb) == 0) {
			msg.msg_namelen = srx.transport_len;

			code = htonl(skb->priority);

			whdr.epoch	= htonl(sp->hdr.epoch);
			whdr.cid	= htonl(sp->hdr.cid);
			whdr.callNumber	= htonl(sp->hdr.callNumber);
			whdr.serviceId	= htons(sp->hdr.serviceId);
			whdr.flags	= sp->hdr.flags;
			whdr.flags	^= RXRPC_CLIENT_INITIATED;
			whdr.flags	&= RXRPC_CLIENT_INITIATED;

			kernel_sendmsg(local->socket, &msg, iov, 2, size);
		}

		rxrpc_free_skb(skb, rxrpc_skb_rx_freed);
	}

	_leave("");
}
예제 #4
0
/*
 * Discard a packet we've used up and advance the Rx window by one.
 */
static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
{
    struct rxrpc_skb_priv *sp;
    struct sk_buff *skb;
    rxrpc_serial_t serial;
    rxrpc_seq_t hard_ack, top;
    u8 flags;
    int ix;

    _enter("%d", call->debug_id);

    hard_ack = call->rx_hard_ack;
    top = smp_load_acquire(&call->rx_top);
    ASSERT(before(hard_ack, top));

    hard_ack++;
    ix = hard_ack & RXRPC_RXTX_BUFF_MASK;
    skb = call->rxtx_buffer[ix];
    rxrpc_see_skb(skb, rxrpc_skb_rx_rotated);
    sp = rxrpc_skb(skb);
    flags = sp->hdr.flags;
    serial = sp->hdr.serial;
    if (call->rxtx_annotations[ix] & RXRPC_RX_ANNO_JUMBO)
        serial += (call->rxtx_annotations[ix] & RXRPC_RX_ANNO_JUMBO) - 1;

    call->rxtx_buffer[ix] = NULL;
    call->rxtx_annotations[ix] = 0;
    /* Barrier against rxrpc_input_data(). */
    smp_store_release(&call->rx_hard_ack, hard_ack);

    rxrpc_free_skb(skb, rxrpc_skb_rx_freed);

    _debug("%u,%u,%02x", hard_ack, top, flags);
    trace_rxrpc_receive(call, rxrpc_receive_rotate, serial, hard_ack);
    if (flags & RXRPC_LAST_PACKET) {
        rxrpc_end_rx_phase(call, serial);
    } else {
        /* Check to see if there's an ACK that needs sending. */
        if (after_eq(hard_ack, call->ackr_consumed + 2) ||
                after_eq(top, call->ackr_seen + 2) ||
                (hard_ack == top && after(hard_ack, call->ackr_consumed)))
            rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, 0, serial,
                              true, false,
                              rxrpc_propose_ack_rotate_rx);
        if (call->ackr_reason)
            rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ACK);
    }
}
예제 #5
0
/*
 * Perform retransmission of NAK'd and unack'd packets.
 */
static void rxrpc_resend(struct rxrpc_call *call, ktime_t now)
{
	struct rxrpc_skb_priv *sp;
	struct sk_buff *skb;
	rxrpc_seq_t cursor, seq, top;
	ktime_t max_age, oldest, ack_ts;
	int ix;
	u8 annotation, anno_type, retrans = 0, unacked = 0;

	_enter("{%d,%d}", call->tx_hard_ack, call->tx_top);

	max_age = ktime_sub_ms(now, rxrpc_resend_timeout);

	spin_lock_bh(&call->lock);

	cursor = call->tx_hard_ack;
	top = call->tx_top;
	ASSERT(before_eq(cursor, top));
	if (cursor == top)
		goto out_unlock;

	/* Scan the packet list without dropping the lock and decide which of
	 * the packets in the Tx buffer we're going to resend and what the new
	 * resend timeout will be.
	 */
	oldest = now;
	for (seq = cursor + 1; before_eq(seq, top); seq++) {
		ix = seq & RXRPC_RXTX_BUFF_MASK;
		annotation = call->rxtx_annotations[ix];
		anno_type = annotation & RXRPC_TX_ANNO_MASK;
		annotation &= ~RXRPC_TX_ANNO_MASK;
		if (anno_type == RXRPC_TX_ANNO_ACK)
			continue;

		skb = call->rxtx_buffer[ix];
		rxrpc_see_skb(skb, rxrpc_skb_tx_seen);
		sp = rxrpc_skb(skb);

		if (anno_type == RXRPC_TX_ANNO_UNACK) {
			if (ktime_after(skb->tstamp, max_age)) {
				if (ktime_before(skb->tstamp, oldest))
					oldest = skb->tstamp;
				continue;
			}
			if (!(annotation & RXRPC_TX_ANNO_RESENT))
				unacked++;
		}

		/* Okay, we need to retransmit a packet. */
		call->rxtx_annotations[ix] = RXRPC_TX_ANNO_RETRANS | annotation;
		retrans++;
		trace_rxrpc_retransmit(call, seq, annotation | anno_type,
				       ktime_to_ns(ktime_sub(skb->tstamp, max_age)));
	}

	call->resend_at = ktime_add_ms(oldest, rxrpc_resend_timeout);

	if (unacked)
		rxrpc_congestion_timeout(call);

	/* If there was nothing that needed retransmission then it's likely
	 * that an ACK got lost somewhere.  Send a ping to find out instead of
	 * retransmitting data.
	 */
	if (!retrans) {
		rxrpc_set_timer(call, rxrpc_timer_set_for_resend, now);
		spin_unlock_bh(&call->lock);
		ack_ts = ktime_sub(now, call->acks_latest_ts);
		if (ktime_to_ns(ack_ts) < call->peer->rtt)
			goto out;
		rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
				  rxrpc_propose_ack_ping_for_lost_ack);
		rxrpc_send_ack_packet(call, true);
		goto out;
	}

	/* Now go through the Tx window and perform the retransmissions.  We
	 * have to drop the lock for each send.  If an ACK comes in whilst the
	 * lock is dropped, it may clear some of the retransmission markers for
	 * packets that it soft-ACKs.
	 */
	for (seq = cursor + 1; before_eq(seq, top); seq++) {
		ix = seq & RXRPC_RXTX_BUFF_MASK;
		annotation = call->rxtx_annotations[ix];
		anno_type = annotation & RXRPC_TX_ANNO_MASK;
		if (anno_type != RXRPC_TX_ANNO_RETRANS)
			continue;

		skb = call->rxtx_buffer[ix];
		rxrpc_get_skb(skb, rxrpc_skb_tx_got);
		spin_unlock_bh(&call->lock);

		if (rxrpc_send_data_packet(call, skb, true) < 0) {
			rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
			return;
		}

		if (rxrpc_is_client_call(call))
			rxrpc_expose_client_call(call);

		rxrpc_free_skb(skb, rxrpc_skb_tx_freed);
		spin_lock_bh(&call->lock);

		/* We need to clear the retransmit state, but there are two
		 * things we need to be aware of: A new ACK/NAK might have been
		 * received and the packet might have been hard-ACK'd (in which
		 * case it will no longer be in the buffer).
		 */
		if (after(seq, call->tx_hard_ack)) {
			annotation = call->rxtx_annotations[ix];
			anno_type = annotation & RXRPC_TX_ANNO_MASK;
			if (anno_type == RXRPC_TX_ANNO_RETRANS ||
			    anno_type == RXRPC_TX_ANNO_NAK) {
				annotation &= ~RXRPC_TX_ANNO_MASK;
				annotation |= RXRPC_TX_ANNO_UNACK;
			}
			annotation |= RXRPC_TX_ANNO_RESENT;
			call->rxtx_annotations[ix] = annotation;
		}

		if (after(call->tx_hard_ack, seq))
			seq = call->tx_hard_ack;
	}

out_unlock:
	spin_unlock_bh(&call->lock);
out:
	_leave("");
}
예제 #6
0
/*
 * Deliver messages to a call.  This keeps processing packets until the buffer
 * is filled and we find either more DATA (returns 0) or the end of the DATA
 * (returns 1).  If more packets are required, it returns -EAGAIN.
 */
static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
                              struct msghdr *msg, struct iov_iter *iter,
                              size_t len, int flags, size_t *_offset)
{
    struct rxrpc_skb_priv *sp;
    struct sk_buff *skb;
    rxrpc_seq_t hard_ack, top, seq;
    size_t remain;
    bool last;
    unsigned int rx_pkt_offset, rx_pkt_len;
    int ix, copy, ret = -EAGAIN, ret2;

    rx_pkt_offset = call->rx_pkt_offset;
    rx_pkt_len = call->rx_pkt_len;

    if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) {
        seq = call->rx_hard_ack;
        ret = 1;
        goto done;
    }

    /* Barriers against rxrpc_input_data(). */
    hard_ack = call->rx_hard_ack;
    top = smp_load_acquire(&call->rx_top);
    for (seq = hard_ack + 1; before_eq(seq, top); seq++) {
        ix = seq & RXRPC_RXTX_BUFF_MASK;
        skb = call->rxtx_buffer[ix];
        if (!skb) {
            trace_rxrpc_recvmsg(call, rxrpc_recvmsg_hole, seq,
                                rx_pkt_offset, rx_pkt_len, 0);
            break;
        }
        smp_rmb();
        rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
        sp = rxrpc_skb(skb);

        if (!(flags & MSG_PEEK))
            trace_rxrpc_receive(call, rxrpc_receive_front,
                                sp->hdr.serial, seq);

        if (msg)
            sock_recv_timestamp(msg, sock->sk, skb);

        if (rx_pkt_offset == 0) {
            ret2 = rxrpc_locate_data(call, skb,
                                     &call->rxtx_annotations[ix],
                                     &rx_pkt_offset, &rx_pkt_len);
            trace_rxrpc_recvmsg(call, rxrpc_recvmsg_next, seq,
                                rx_pkt_offset, rx_pkt_len, ret2);
            if (ret2 < 0) {
                ret = ret2;
                goto out;
            }
        } else {
            trace_rxrpc_recvmsg(call, rxrpc_recvmsg_cont, seq,
                                rx_pkt_offset, rx_pkt_len, 0);
        }

        /* We have to handle short, empty and used-up DATA packets. */
        remain = len - *_offset;
        copy = rx_pkt_len;
        if (copy > remain)
            copy = remain;
        if (copy > 0) {
            ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter,
                                          copy);
            if (ret2 < 0) {
                ret = ret2;
                goto out;
            }

            /* handle piecemeal consumption of data packets */
            rx_pkt_offset += copy;
            rx_pkt_len -= copy;
            *_offset += copy;
        }

        if (rx_pkt_len > 0) {
            trace_rxrpc_recvmsg(call, rxrpc_recvmsg_full, seq,
                                rx_pkt_offset, rx_pkt_len, 0);
            ASSERTCMP(*_offset, ==, len);
            ret = 0;
            break;
        }

        /* The whole packet has been transferred. */
        last = sp->hdr.flags & RXRPC_LAST_PACKET;
        if (!(flags & MSG_PEEK))
            rxrpc_rotate_rx_window(call);
        rx_pkt_offset = 0;
        rx_pkt_len = 0;

        if (last) {
            ASSERTCMP(seq, ==, READ_ONCE(call->rx_top));
            ret = 1;
            goto out;
        }
    }