Commit fe276637 authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] Avoid the use of constant SCTP_IP_OVERHEAD to determine the

max data size in a SCTP packet.

Calculate the overhead based on the socket's protocol family header
length.
parent 321fe6f8
......@@ -57,15 +57,6 @@ enum { SCTP_MAX_STREAM = 0xffff };
enum { SCTP_DEFAULT_OUTSTREAMS = 10 };
enum { SCTP_DEFAULT_INSTREAMS = SCTP_MAX_STREAM };
/* Define the amount of space to reserve for SCTP, IP, LL.
* There is a little bit of waste that we are always allocating
* for ipv6 headers, but this seems worth the simplicity.
*/
#define SCTP_IP_OVERHEAD ((sizeof(struct sctphdr)\
+ sizeof(struct ipv6hdr)\
+ MAX_HEADER))
/* Since CIDs are sparse, we need all four of the following
* symbols. CIDs are dense through SCTP_CID_BASE_MAX.
*/
......
......@@ -437,12 +437,15 @@ static inline __s32 sctp_jitter(__u32 rto)
static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu)
{
int frag = pmtu;
frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
frag -= sizeof(struct sctp_sack_chunk);
frag -= sp->pf->af->net_header_len;
frag -= sizeof(struct sctphdr) + sizeof(struct sctp_data_chunk);
if (sp->user_frag)
frag = min_t(int, frag, sp->user_frag);
frag = min_t(int, frag, SCTP_MAX_CHUNK_LEN);
return frag;
}
......
......@@ -667,6 +667,9 @@ struct sctp_packet {
/* This contains the payload chunks. */
struct sk_buff_head chunks;
/* This is the overhead of the sctp and ip headers. */
size_t overhead;
/* This is the total size of all chunks INCLUDING padding. */
size_t size;
......@@ -721,6 +724,10 @@ sctp_outq_ohandler_t sctp_packet_transmit_chunk;
sctp_outq_ohandler_force_t sctp_packet_transmit;
void sctp_packet_free(struct sctp_packet *);
static inline int sctp_packet_empty(struct sctp_packet *packet)
{
return (packet->size == packet->overhead);
}
/* This represents a remote transport address.
* For local transport addresses, we just use union sctp_addr.
......
......@@ -192,24 +192,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
msg->can_expire = 1;
}
/* What is a reasonable fragmentation point right now? */
max = asoc->pmtu;
if (max < SCTP_MIN_PMTU)
max = SCTP_MIN_PMTU;
max -= SCTP_IP_OVERHEAD;
/* Make sure not beyond maximum chunk size. */
if (max > SCTP_MAX_CHUNK_LEN)
max = SCTP_MAX_CHUNK_LEN;
/* Subtract out the overhead of a data chunk header. */
max -= sizeof(struct sctp_data_chunk);
whole = 0;
/* If user has specified smaller fragmentation, make it so. */
if (sctp_sk(asoc->base.sk)->user_frag)
max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag);
max = asoc->frag_point;
whole = 0;
first_len = max;
/* Encourage Cookie-ECHO bundling. */
......
......@@ -73,8 +73,6 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
__u32 vtag, int ecn_capable,
sctp_packet_phandler_t *prepend_handler)
{
int packet_empty = (packet->size == SCTP_IP_OVERHEAD);
packet->vtag = vtag;
packet->ecn_capable = ecn_capable;
packet->get_prepend_chunk = prepend_handler;
......@@ -83,7 +81,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
packet->ipfragok = 0;
/* We might need to call the prepend_handler right away. */
if (packet_empty)
if (sctp_packet_empty(packet))
sctp_packet_reset(packet);
return packet;
}
......@@ -93,11 +91,22 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
struct sctp_transport *transport,
__u16 sport, __u16 dport)
{
struct sctp_association *asoc = transport->asoc;
size_t overhead;
packet->transport = transport;
packet->source_port = sport;
packet->destination_port = dport;
skb_queue_head_init(&packet->chunks);
packet->size = SCTP_IP_OVERHEAD;
if (asoc) {
struct sctp_opt *sp = sctp_sk(asoc->base.sk);
overhead = sp->pf->af->net_header_len;
} else {
overhead = sizeof(struct ipv6hdr);
}
overhead += sizeof(struct sctphdr);
packet->overhead = overhead;
packet->size = overhead;
packet->vtag = 0;
packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL;
......@@ -215,17 +224,14 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
/* Decide if we need to fragment or resubmit later. */
if (too_big) {
int packet_empty = (packet->size == SCTP_IP_OVERHEAD);
/* Both control chunks and data chunks with TSNs are
* non-fragmentable.
*/
if (packet_empty || !sctp_chunk_is_data(chunk)) {
if (sctp_packet_empty(packet) || !sctp_chunk_is_data(chunk)) {
/* We no longer do re-fragmentation.
* Just fragment at the IP layer, if we
* actually hit this condition
*/
packet->ipfragok = 1;
goto append;
......@@ -297,7 +303,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
goto nomem;
/* Make sure the outbound skb has enough header room reserved. */
skb_reserve(nskb, SCTP_IP_OVERHEAD);
skb_reserve(nskb, packet->overhead);
/* Set the owning socket so that we know where to get the
* destination IP address.
......@@ -471,7 +477,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
out:
packet->size = SCTP_IP_OVERHEAD;
packet->size = packet->overhead;
return err;
no_route:
kfree_skb(nskb);
......@@ -497,7 +503,6 @@ int sctp_packet_transmit(struct sctp_packet *packet)
goto out;
nomem:
err = -ENOMEM;
printk("%s alloc_skb failed.\n", __FUNCTION__);
goto err;
}
......@@ -512,7 +517,7 @@ static void sctp_packet_reset(struct sctp_packet *packet)
{
struct sctp_chunk *chunk = NULL;
packet->size = SCTP_IP_OVERHEAD;
packet->size = packet->overhead;
if (packet->get_prepend_chunk)
chunk = packet->get_prepend_chunk(packet->transport->asoc);
......@@ -609,7 +614,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* if any previously transmitted data on the connection remains
* unacknowledged.
*/
if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
if (!sp->nodelay && sctp_packet_empty(packet) &&
q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
unsigned len = datasize + q->out_qlen;
......@@ -617,7 +622,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* data will fit or delay in hopes of bundling a full
* sized packet.
*/
if (len < asoc->pmtu - SCTP_IP_OVERHEAD) {
if (len < asoc->pmtu - packet->overhead) {
retval = SCTP_XMIT_NAGLE_DELAY;
goto finish;
}
......
......@@ -926,7 +926,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
transport = t;
packet = &transport->packet;
if (packet->size != SCTP_IP_OVERHEAD)
if (!sctp_packet_empty(packet))
error = (*q->force_output)(packet);
}
......
......@@ -1948,6 +1948,9 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen)
*/
static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
{
struct sctp_association *asoc;
struct list_head *pos;
struct sctp_opt *sp = sctp_sk(sk);
int val;
if (optlen < sizeof(int))
......@@ -1956,7 +1959,15 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
return -EFAULT;
if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))
return -EINVAL;
sctp_sk(sk)->user_frag = val;
sp->user_frag = val;
if (val) {
/* Update the frag_point of the existing associations. */
list_for_each(pos, &(sp->ep->asocs)) {
asoc = list_entry(pos, struct sctp_association, asocs);
asoc->frag_point = sctp_frag_point(sp, asoc->pmtu);
}
}
return 0;
}
......@@ -2531,10 +2542,6 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
status.sstat_instrms = asoc->c.sinit_max_instreams;
status.sstat_outstrms = asoc->c.sinit_num_ostreams;
/* Just in time frag_point update. */
if (sctp_sk(sk)->user_frag)
asoc->frag_point
= min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag);
status.sstat_fragmentation_point = asoc->frag_point;
status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
memcpy(&status.sstat_primary.spinfo_address,
......
......@@ -839,6 +839,9 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
sctp_ulpevent_set_owner(event, asoc);
sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
if (!skb->data_len)
return;
/* Note: Not clearing the entire event struct as this is just a
* fragment of the real event. However, we still need to do rwnd
* accounting.
......@@ -867,6 +870,9 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
skb = sctp_event2skb(event);
sctp_assoc_rwnd_increase(event->asoc, skb_headlen(skb));
if (!skb->data_len)
goto done;
/* Don't forget the fragments. */
for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
/* NOTE: skb_shinfos are recursive. Although IP returns
......@@ -875,6 +881,8 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
*/
sctp_ulpevent_release_data(sctp_skb2event(frag));
}
done:
sctp_ulpevent_release_owner(event);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment