Skip to content

Commit

Permalink
sctp: do the basic send and recv for PLPMTUD probe
Browse files Browse the repository at this point in the history
This patch does exactly what rfc8899#section-6.2.1.2 says:

   The SCTP sender needs to be able to determine the total size of a
   probe packet.  The HEARTBEAT chunk could carry a Heartbeat
   Information parameter that includes, besides the information
   suggested in [RFC4960], the probe size to help an implementation
   associate a HEARTBEAT ACK with the size of probe that was sent.  The
   sender could also use other methods, such as sending a nonce and
   verifying the information returned also contains the corresponding
   nonce.  The length of the PAD chunk is computed by reducing the
   probing size by the size of the SCTP common header and the HEARTBEAT
   chunk.

Note that HB ACK chunk will carry back whatever HB chunk carried, including
the probe_size we put it in; We also check hbinfo->probe_size in the HB ACK
against link->pl.probe_size to validate this HB ACK chunk.

v1->v2:
  - Remove the unused 'sp' and add static for sctp_packet_bundle_pad().

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Xin Long authored and David S. Miller committed Jun 22, 2021
1 parent 92548ec commit fe59379
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 7 deletions.
3 changes: 2 additions & 1 deletion include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ struct sctp_chunk *sctp_make_new_encap_port(
const struct sctp_association *asoc,
const struct sctp_chunk *chunk);
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport);
const struct sctp_transport *transport,
__u32 probe_size);
struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
const void *payload,
Expand Down
2 changes: 2 additions & 0 deletions include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ struct sctp_sender_hb_info {
union sctp_addr daddr;
unsigned long sent_at;
__u64 hb_nonce;
__u32 probe_size;
};

int sctp_stream_init(struct sctp_stream *stream, __u16 outcnt, __u16 incnt,
Expand Down Expand Up @@ -657,6 +658,7 @@ struct sctp_chunk {
data_accepted:1, /* At least 1 chunk accepted */
auth:1, /* IN: was auth'ed | OUT: needs auth */
has_asconf:1, /* IN: have seen an asconf before */
pmtu_probe:1, /* Used by PLPMTUD, can be set in s HB chunk */
tsn_missing_report:2, /* Data chunk missing counter. */
fast_retransmit:2; /* Is this chunk fast retransmitted? */
};
Expand Down
30 changes: 29 additions & 1 deletion net/sctp/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,30 @@ enum sctp_xmit sctp_packet_transmit_chunk(struct sctp_packet *packet,
return retval;
}

/* Try to bundle a pad chunk into a packet with a heartbeat chunk for PLPMTUTD probe */
static enum sctp_xmit sctp_packet_bundle_pad(struct sctp_packet *pkt, struct sctp_chunk *chunk)
{
struct sctp_transport *t = pkt->transport;
struct sctp_chunk *pad;
int overhead = 0;

if (!chunk->pmtu_probe)
return SCTP_XMIT_OK;

/* calculate the Padding Data size for the pad chunk */
overhead += sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr);
overhead += sizeof(struct sctp_sender_hb_info) + sizeof(struct sctp_pad_chunk);
pad = sctp_make_pad(t->asoc, t->pl.probe_size - overhead);
if (!pad)
return SCTP_XMIT_DELAY;

list_add_tail(&pad->list, &pkt->chunk_list);
pkt->size += SCTP_PAD4(ntohs(pad->chunk_hdr->length));
chunk->transport = t;

return SCTP_XMIT_OK;
}

/* Try to bundle an auth chunk into the packet. */
static enum sctp_xmit sctp_packet_bundle_auth(struct sctp_packet *pkt,
struct sctp_chunk *chunk)
Expand Down Expand Up @@ -382,6 +406,10 @@ enum sctp_xmit sctp_packet_append_chunk(struct sctp_packet *packet,
goto finish;

retval = __sctp_packet_append_chunk(packet, chunk);
if (retval != SCTP_XMIT_OK)
goto finish;

retval = sctp_packet_bundle_pad(packet, chunk);

finish:
return retval;
Expand Down Expand Up @@ -553,7 +581,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
sk = chunk->skb->sk;

/* check gso */
if (packet->size > tp->pathmtu && !packet->ipfragok) {
if (packet->size > tp->pathmtu && !packet->ipfragok && !chunk->pmtu_probe) {
if (!sk_can_gso(sk)) {
pr_err_once("Trying to GSO but underlying device doesn't support it.");
goto out;
Expand Down
13 changes: 11 additions & 2 deletions net/sctp/outqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,11 @@ static int sctp_packet_singleton(struct sctp_transport *transport,

sctp_packet_init(&singleton, transport, sport, dport);
sctp_packet_config(&singleton, vtag, 0);
sctp_packet_append_chunk(&singleton, chunk);
if (sctp_packet_append_chunk(&singleton, chunk) != SCTP_XMIT_OK) {
list_del_init(&chunk->list);
sctp_chunk_free(chunk);
return -ENOMEM;
}
return sctp_packet_transmit(&singleton, gfp);
}

Expand Down Expand Up @@ -929,8 +933,13 @@ static void sctp_outq_flush_ctrl(struct sctp_flush_ctx *ctx)
one_packet = 1;
fallthrough;

case SCTP_CID_SACK:
case SCTP_CID_HEARTBEAT:
if (chunk->pmtu_probe) {
sctp_packet_singleton(ctx->transport, chunk, ctx->gfp);
break;
}
fallthrough;
case SCTP_CID_SACK:
case SCTP_CID_SHUTDOWN:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ASCONF:
Expand Down
5 changes: 4 additions & 1 deletion net/sctp/sm_make_chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,8 @@ struct sctp_chunk *sctp_make_new_encap_port(const struct sctp_association *asoc,

/* Make a HEARTBEAT chunk. */
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport)
const struct sctp_transport *transport,
__u32 probe_size)
{
struct sctp_sender_hb_info hbinfo;
struct sctp_chunk *retval;
Expand All @@ -1176,13 +1177,15 @@ struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
hbinfo.daddr = transport->ipaddr;
hbinfo.sent_at = jiffies;
hbinfo.hb_nonce = transport->hb_nonce;
hbinfo.probe_size = probe_size;

/* Cast away the 'const', as this is just telling the chunk
* what transport it belongs to.
*/
retval->transport = (struct sctp_transport *) transport;
retval->subh.hbs_hdr = sctp_addto_chunk(retval, sizeof(hbinfo),
&hbinfo);
retval->pmtu_probe = !!probe_size;

nodata:
return retval;
Expand Down
20 changes: 18 additions & 2 deletions net/sctp/sm_statefuns.c
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,7 @@ static enum sctp_disposition sctp_sf_heartbeat(
struct sctp_chunk *reply;

/* Send a heartbeat to our peer. */
reply = sctp_make_heartbeat(asoc, transport);
reply = sctp_make_heartbeat(asoc, transport, 0);
if (!reply)
return SCTP_DISPOSITION_NOMEM;

Expand Down Expand Up @@ -1104,8 +1104,15 @@ enum sctp_disposition sctp_sf_send_probe(struct net *net,
struct sctp_cmd_seq *commands)
{
struct sctp_transport *transport = (struct sctp_transport *)arg;
struct sctp_chunk *reply;

if (!sctp_transport_pl_enabled(transport))
return SCTP_DISPOSITION_CONSUME;

/* The actual handling will be performed here in a later patch. */
reply = sctp_make_heartbeat(asoc, transport, transport->pl.probe_size);
if (!reply)
return SCTP_DISPOSITION_NOMEM;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
sctp_add_cmd_sf(commands, SCTP_CMD_PROBE_TIMER_UPDATE,
SCTP_TRANSPORT(transport));

Expand Down Expand Up @@ -1260,6 +1267,15 @@ enum sctp_disposition sctp_sf_backbeat_8_3(struct net *net,
if (hbinfo->hb_nonce != link->hb_nonce)
return SCTP_DISPOSITION_DISCARD;

if (hbinfo->probe_size) {
if (hbinfo->probe_size != link->pl.probe_size ||
!sctp_transport_pl_enabled(link))
return SCTP_DISPOSITION_DISCARD;

/* The actual handling will be performed here in a later patch. */
return SCTP_DISPOSITION_CONSUME;
}

max_interval = link->hbinterval + link->rto;

/* Check if the timestamp looks valid. */
Expand Down

0 comments on commit fe59379

Please sign in to comment.