rxrpc: Use info in skbuff instead of reparsing a jumbo packet
Use the information now cached in the skbuff private data to avoid the need
to reparse a jumbo packet. We can find all the subpackets by dead
reckoning, so it's only necessary to note how many there are, whether the
last one is flagged as LAST_PACKET and whether any have the REQUEST_ACK
flag set.
This is necessary as once recvmsg() can see the packet, it can start
modifying it, such as doing in-place decryption.
Fixes: 248f219cb8
("rxrpc: Rewrite the data and ack handling code")
Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -177,7 +177,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
|
||||
struct sk_buff *skb;
|
||||
rxrpc_serial_t serial;
|
||||
rxrpc_seq_t hard_ack, top;
|
||||
u8 flags;
|
||||
bool last = false;
|
||||
u8 subpacket;
|
||||
int ix;
|
||||
|
||||
_enter("%d", call->debug_id);
|
||||
@@ -191,10 +192,13 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
|
||||
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;
|
||||
|
||||
subpacket = call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
|
||||
serial = sp->hdr.serial + subpacket;
|
||||
|
||||
if (subpacket == sp->nr_subpackets - 1 &&
|
||||
sp->rx_flags & RXRPC_SKB_INCL_LAST)
|
||||
last = true;
|
||||
|
||||
call->rxtx_buffer[ix] = NULL;
|
||||
call->rxtx_annotations[ix] = 0;
|
||||
@@ -203,9 +207,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
|
||||
|
||||
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) {
|
||||
if (last) {
|
||||
rxrpc_end_rx_phase(call, serial);
|
||||
} else {
|
||||
/* Check to see if there's an ACK that needs sending. */
|
||||
@@ -233,18 +236,19 @@ static int rxrpc_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
rxrpc_seq_t seq = sp->hdr.seq;
|
||||
u16 cksum = sp->hdr.cksum;
|
||||
u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
|
||||
|
||||
_enter("");
|
||||
|
||||
/* For all but the head jumbo subpacket, the security checksum is in a
|
||||
* jumbo header immediately prior to the data.
|
||||
*/
|
||||
if ((annotation & RXRPC_RX_ANNO_JUMBO) > 1) {
|
||||
if (subpacket > 0) {
|
||||
__be16 tmp;
|
||||
if (skb_copy_bits(skb, offset - 2, &tmp, 2) < 0)
|
||||
BUG();
|
||||
cksum = ntohs(tmp);
|
||||
seq += (annotation & RXRPC_RX_ANNO_JUMBO) - 1;
|
||||
seq += subpacket;
|
||||
}
|
||||
|
||||
return call->conn->security->verify_packet(call, skb, offset, len,
|
||||
@@ -265,19 +269,18 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
|
||||
u8 *_annotation,
|
||||
unsigned int *_offset, unsigned int *_len)
|
||||
{
|
||||
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
|
||||
unsigned int offset = sizeof(struct rxrpc_wire_header);
|
||||
unsigned int len;
|
||||
int ret;
|
||||
u8 annotation = *_annotation;
|
||||
u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
|
||||
|
||||
/* Locate the subpacket */
|
||||
offset += subpacket * RXRPC_JUMBO_SUBPKTLEN;
|
||||
len = skb->len - offset;
|
||||
if ((annotation & RXRPC_RX_ANNO_JUMBO) > 0) {
|
||||
offset += (((annotation & RXRPC_RX_ANNO_JUMBO) - 1) *
|
||||
RXRPC_JUMBO_SUBPKTLEN);
|
||||
len = (annotation & RXRPC_RX_ANNO_JLAST) ?
|
||||
skb->len - offset : RXRPC_JUMBO_SUBPKTLEN;
|
||||
}
|
||||
if (subpacket < sp->nr_subpackets - 1)
|
||||
len = RXRPC_JUMBO_DATALEN;
|
||||
|
||||
if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) {
|
||||
ret = rxrpc_verify_packet(call, skb, annotation, offset, len);
|
||||
@@ -303,6 +306,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
|
||||
{
|
||||
struct rxrpc_skb_priv *sp;
|
||||
struct sk_buff *skb;
|
||||
rxrpc_serial_t serial;
|
||||
rxrpc_seq_t hard_ack, top, seq;
|
||||
size_t remain;
|
||||
bool last;
|
||||
@@ -339,9 +343,12 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
|
||||
rxrpc_see_skb(skb, rxrpc_skb_rx_seen);
|
||||
sp = rxrpc_skb(skb);
|
||||
|
||||
if (!(flags & MSG_PEEK))
|
||||
if (!(flags & MSG_PEEK)) {
|
||||
serial = sp->hdr.serial;
|
||||
serial += call->rxtx_annotations[ix] & RXRPC_RX_ANNO_SUBPACKET;
|
||||
trace_rxrpc_receive(call, rxrpc_receive_front,
|
||||
sp->hdr.serial, seq);
|
||||
serial, seq);
|
||||
}
|
||||
|
||||
if (msg)
|
||||
sock_recv_timestamp(msg, sock->sk, skb);
|
||||
|
Reference in New Issue
Block a user