diff --git a/homa_incoming.c b/homa_incoming.c index 9e72c521..981e9584 100644 --- a/homa_incoming.c +++ b/homa_incoming.c @@ -806,17 +806,15 @@ void homa_grant_pkt(struct sk_buff *skb, struct homa_rpc *rpc) __must_hold(rpc->bucket->lock) { struct homa_grant_hdr *h = (struct homa_grant_hdr *)skb->data; - int new_offset = ntohl(h->offset); + u32 new_offset = ntohl(h->offset); tt_record4("processing grant for id %llu, offset %d, priority %d, increment %d", homa_local_id(h->common.sender_id), ntohl(h->offset), h->priority, new_offset - rpc->msgout.granted); if (rpc->state == RPC_OUTGOING) { - if (new_offset > rpc->msgout.granted) { - rpc->msgout.granted = new_offset; - if (new_offset > rpc->msgout.length) - rpc->msgout.granted = rpc->msgout.length; - } + if (new_offset > rpc->msgout.granted) + rpc->msgout.granted = min_t(u32, new_offset, + rpc->msgout.length); rpc->msgout.sched_priority = h->priority; homa_xmit_data(rpc); } diff --git a/test/unit_homa_incoming.c b/test/unit_homa_incoming.c index 74b4b05e..cfa23a45 100644 --- a/test/unit_homa_incoming.c +++ b/test/unit_homa_incoming.c @@ -1874,6 +1874,50 @@ TEST_F(homa_incoming, homa_grant_pkt__grant_past_end_of_message) &h.common, 0, 0)); EXPECT_EQ(20000, crpc->msgout.granted); } +TEST_F(homa_incoming, homa_grant_pkt__offset_is_unsigned) +{ + /* A GRANT's offset is an unsigned wire field. Reading it into a signed + * int makes an offset with the top bit set (>= 2GB) negative, so the + * "new_offset > granted" test fails and the grant is silently dropped + * instead of being clamped to the message length. Treat it as u32 so + * the existing >granted / clamp-to-length logic bounds it correctly. + * + * Table-driven: each row is a grant offset and the granted value it + * should produce for a 20000-byte outgoing message. + */ + struct homa_rpc *crpc = unit_client_rpc(&self->hsk, + UNIT_OUTGOING, self->client_ip, self->server_ip, + self->server_port, self->client_id, 20000, 1600); + static const struct { + const char *name; + u32 offset; + int exp_granted; + } cases[] = { + {"normal_grant_advances", 12000, 12000}, + {"grant_past_end_clamps_to_length", 25000, 20000}, + {"high_bit_offset_clamps_not_ignored", 0x80000000, 20000}, + }; + int i; + + ASSERT_NE(NULL, crpc); + for (i = 0; i < (int)ARRAY_SIZE(cases); i++) { + struct homa_grant_hdr h = {{.sport = htons(self->server_port), + .dport = htons(self->hsk.port), + .sender_id = cpu_to_be64(self->server_id), + .type = GRANT}, + .offset = htonl(cases[i].offset), + .priority = 3}; + + TH_LOG("case: %s", cases[i].name); + crpc->state = RPC_OUTGOING; + crpc->msgout.granted = 5000; + unit_log_clear(); + homa_dispatch_pkts(mock_skb_alloc(self->client_ip, + self->server_ip, + &h.common, 0, 0)); + EXPECT_EQ(cases[i].exp_granted, crpc->msgout.granted); + } +} #endif /* See strip.py */ TEST_F(homa_incoming, homa_resend_pkt__unknown_rpc)