Commit c5d01dcf authored by Jon Grimm's avatar Jon Grimm

[SCTP] Add sinfo_timetolive support.

sinfo_timetolive lets the application specify 'timed reliability'
for a message.  That is, the message really only has a use to
the peer up to this timeout.  Without PR-SCTP, we can throw away
such timed out messages if we haven't yet assigned TSN/SSNs to
them.  If we have, there is nothing we can do until we support
PR-SCTP extension.  
parent 7b3a0a8c
...@@ -450,7 +450,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id) ...@@ -450,7 +450,7 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
} }
/* Structure to track chunk fragments that have been acked, but peer /* Structure to track chunk fragments that have been acked, but peer
* fragments of the same message have not. * fragments of the same message have not.
*/ */
struct sctp_datamsg { struct sctp_datamsg {
/* Chunks waiting to be submitted to lower layer. */ /* Chunks waiting to be submitted to lower layer. */
...@@ -459,9 +459,13 @@ struct sctp_datamsg { ...@@ -459,9 +459,13 @@ struct sctp_datamsg {
struct list_head track; struct list_head track;
/* Reference counting. */ /* Reference counting. */
atomic_t refcnt; atomic_t refcnt;
/* When is this message no longer interesting to the peer? */
unsigned long expires_at;
/* Did the messenge fail to send? */ /* Did the messenge fail to send? */
int send_error; int send_error;
char send_failed; char send_failed;
/* Control whether fragments from this message can expire. */
char can_expire;
}; };
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
...@@ -473,6 +477,9 @@ void sctp_datamsg_hold(struct sctp_datamsg *); ...@@ -473,6 +477,9 @@ void sctp_datamsg_hold(struct sctp_datamsg *);
void sctp_datamsg_free(struct sctp_datamsg *); void sctp_datamsg_free(struct sctp_datamsg *);
void sctp_datamsg_track(struct sctp_chunk *); void sctp_datamsg_track(struct sctp_chunk *);
void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *); void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
void sctp_datamsg_fail(struct sctp_chunk *, int error);
int sctp_datamsg_expires(struct sctp_chunk *);
/* RFC2960 1.4 Key Terms /* RFC2960 1.4 Key Terms
* *
...@@ -545,18 +552,6 @@ struct sctp_chunk { ...@@ -545,18 +552,6 @@ struct sctp_chunk {
/* We fill this in if we are calculating RTT. */ /* We fill this in if we are calculating RTT. */
unsigned long sent_at; unsigned long sent_at;
__u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */
__u8 resent; /* Has this chunk ever been retransmitted. */
__u8 has_tsn; /* Does this chunk have a TSN yet? */
__u8 has_ssn; /* Does this chunk have a SSN yet? */
__u8 singleton; /* Was this the only chunk in the packet? */
__u8 end_of_packet; /* Was this the last chunk in the packet? */
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */
/* What is the origin IP address for this chunk? */ /* What is the origin IP address for this chunk? */
union sctp_addr source; union sctp_addr source;
/* Destination address for this chunk. */ /* Destination address for this chunk. */
...@@ -570,6 +565,18 @@ struct sctp_chunk { ...@@ -570,6 +565,18 @@ struct sctp_chunk {
* go. It is NULL if we have no preference. * go. It is NULL if we have no preference.
*/ */
struct sctp_transport *transport; struct sctp_transport *transport;
__u8 rtt_in_progress; /* Is this chunk used for RTT calculation? */
__u8 resent; /* Has this chunk ever been retransmitted. */
__u8 has_tsn; /* Does this chunk have a TSN yet? */
__u8 has_ssn; /* Does this chunk have a SSN yet? */
__u8 singleton; /* Was this the only chunk in the packet? */
__u8 end_of_packet; /* Was this the last chunk in the packet? */
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
__u8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */
}; };
void sctp_chunk_hold(struct sctp_chunk *); void sctp_chunk_hold(struct sctp_chunk *);
...@@ -580,10 +587,10 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type, ...@@ -580,10 +587,10 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type,
__u8 flags, int size); __u8 flags, int size);
void sctp_chunk_free(struct sctp_chunk *); void sctp_chunk_free(struct sctp_chunk *);
void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
struct sctp_chunk *sctp_chunkify(struct sk_buff *, struct sctp_chunk *sctp_chunkify(struct sk_buff *,
const struct sctp_association *, const struct sctp_association *,
struct sock *); struct sock *);
void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *,
union sctp_addr *); union sctp_addr *);
const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
...@@ -847,7 +854,7 @@ struct sctp_transport { ...@@ -847,7 +854,7 @@ struct sctp_transport {
/* A flag which indicates the occurrence of a changeover */ /* A flag which indicates the occurrence of a changeover */
char changeover_active; char changeover_active;
/* A glag which indicates whether the change of primary is /* A glag which indicates whether the change of primary is
* the first switch to this destination address during an * the first switch to this destination address during an
* active switch. * active switch.
...@@ -1024,7 +1031,7 @@ struct sctp_bind_addr { ...@@ -1024,7 +1031,7 @@ struct sctp_bind_addr {
struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask); struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask);
void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port); void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
void sctp_bind_addr_free(struct sctp_bind_addr *); void sctp_bind_addr_free(struct sctp_bind_addr *);
int sctp_bind_addr_copy(struct sctp_bind_addr *dest, int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src, const struct sctp_bind_addr *src,
sctp_scope_t scope, int gfp,int flags); sctp_scope_t scope, int gfp,int flags);
int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
...@@ -1613,7 +1620,7 @@ struct sctp_association { ...@@ -1613,7 +1620,7 @@ struct sctp_association {
/* Need to send an ECNE Chunk? */ /* Need to send an ECNE Chunk? */
char need_ecne; char need_ecne;
/* Is it a temporary association? */ /* Is it a temporary association? */
char temp; char temp;
}; };
......
...@@ -55,8 +55,8 @@ void sctp_datamsg_init(struct sctp_datamsg *msg) ...@@ -55,8 +55,8 @@ void sctp_datamsg_init(struct sctp_datamsg *msg)
atomic_set(&msg->refcnt, 1); atomic_set(&msg->refcnt, 1);
msg->send_failed = 0; msg->send_failed = 0;
msg->send_error = 0; msg->send_error = 0;
msg->can_expire = 0;
INIT_LIST_HEAD(&msg->chunks); INIT_LIST_HEAD(&msg->chunks);
INIT_LIST_HEAD(&msg->track);
} }
/* Allocate and initialize datamsg. */ /* Allocate and initialize datamsg. */
...@@ -84,7 +84,7 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) ...@@ -84,7 +84,7 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
notify = msg->send_failed ? -1 : 0; notify = msg->send_failed ? -1 : 0;
/* Release all references. */ /* Release all references. */
list_for_each_safe(pos, temp, &msg->track) { list_for_each_safe(pos, temp, &msg->chunks) {
list_del(pos); list_del(pos);
chunk = list_entry(pos, struct sctp_chunk, frag_list); chunk = list_entry(pos, struct sctp_chunk, frag_list);
/* Check whether we _really_ need to notify. */ /* Check whether we _really_ need to notify. */
...@@ -94,7 +94,7 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) ...@@ -94,7 +94,7 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
error = msg->send_error; error = msg->send_error;
else else
error = asoc->outqueue.error; error = asoc->outqueue.error;
sp = sctp_sk(asoc->base.sk); sp = sctp_sk(asoc->base.sk);
notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED, notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED,
&sp->subscribe); &sp->subscribe);
...@@ -107,8 +107,8 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg) ...@@ -107,8 +107,8 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
sent = SCTP_DATA_SENT; sent = SCTP_DATA_SENT;
else else
sent = SCTP_DATA_UNSENT; sent = SCTP_DATA_UNSENT;
ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent, ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
error, GFP_ATOMIC); error, GFP_ATOMIC);
if (ev) if (ev)
sctp_ulpq_tail_event(&asoc->ulpq, ev); sctp_ulpq_tail_event(&asoc->ulpq, ev);
...@@ -146,7 +146,6 @@ void sctp_datamsg_free(struct sctp_datamsg *msg) ...@@ -146,7 +146,6 @@ void sctp_datamsg_free(struct sctp_datamsg *msg)
void sctp_datamsg_track(struct sctp_chunk *chunk) void sctp_datamsg_track(struct sctp_chunk *chunk)
{ {
sctp_chunk_hold(chunk); sctp_chunk_hold(chunk);
list_add_tail(&chunk->frag_list, &chunk->msg->track);
} }
/* Assign a chunk to this datamsg. */ /* Assign a chunk to this datamsg. */
...@@ -179,6 +178,20 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -179,6 +178,20 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
if (!msg) if (!msg)
return NULL; return NULL;
/* Note: Calculate this outside of the loop, so that all fragments
* have the same expiration.
*/
if (sinfo->sinfo_timetolive) {
struct timeval tv;
__u32 ttl = sinfo->sinfo_timetolive;
/* sinfo_timetolive is in milliseconds */
tv.tv_sec = ttl / 1000;
tv.tv_usec = ttl % 1000 * 1000;
msg->expires_at = jiffies + timeval_to_jiffies(&tv);
msg->can_expire = 1;
}
/* What is a reasonable fragmentation point right now? */ /* What is a reasonable fragmentation point right now? */
max = asoc->pmtu; max = asoc->pmtu;
if (max < SCTP_MIN_PMTU) if (max < SCTP_MIN_PMTU)
...@@ -191,7 +204,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -191,7 +204,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
/* Subtract out the overhead of a data chunk header. */ /* Subtract out the overhead of a data chunk header. */
max -= sizeof(struct sctp_data_chunk); max -= sizeof(struct sctp_data_chunk);
whole = 0; whole = 0;
/* If user has specified smaller fragmentation, make it so. */ /* If user has specified smaller fragmentation, make it so. */
...@@ -289,3 +301,27 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -289,3 +301,27 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
sctp_datamsg_free(msg); sctp_datamsg_free(msg);
return NULL; return NULL;
} }
/* Check whether this message has expired. */
int sctp_datamsg_expires(struct sctp_chunk *chunk)
{
struct sctp_datamsg *msg = chunk->msg;
/* FIXME: When PR-SCTP is supported we can make this
* check more lenient.
*/
if (!msg->can_expire)
return 0;
if (time_after(jiffies, msg->expires_at))
return 1;
return 0;
}
/* This chunk (and consequently entire message) has failed in its sending. */
void sctp_datamsg_fail(struct sctp_chunk *chunk, int error)
{
chunk->msg->send_failed = 1;
chunk->msg->send_error = error;
}
...@@ -356,6 +356,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -356,6 +356,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
if (sctp_chunk_is_data(chunk)) { if (sctp_chunk_is_data(chunk)) {
if (!chunk->has_tsn) { if (!chunk->has_tsn) {
sctp_chunk_assign_ssn(chunk);
sctp_chunk_assign_tsn(chunk); sctp_chunk_assign_tsn(chunk);
/* 6.3.1 C4) When data is in flight and when allowed /* 6.3.1 C4) When data is in flight and when allowed
...@@ -627,6 +628,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -627,6 +628,8 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
rwnd = 0; rwnd = 0;
asoc->peer.rwnd = rwnd; asoc->peer.rwnd = rwnd;
/* Has been accepted for transmission. */
chunk->msg->can_expire = 0;
finish: finish:
return retval; return retval;
......
...@@ -165,7 +165,7 @@ static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary, ...@@ -165,7 +165,7 @@ static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary,
*/ */
static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn) static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn)
{ {
if (primary->cacc.cycling_changeover && if (primary->cacc.cycling_changeover &&
TSN_lt(tsn, primary->cacc.next_tsn_at_change)) TSN_lt(tsn, primary->cacc.next_tsn_at_change))
return 1; return 1;
return 0; return 0;
...@@ -174,7 +174,7 @@ static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn) ...@@ -174,7 +174,7 @@ static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn)
/* /*
* SFR-CACC algorithm: * SFR-CACC algorithm:
* 3) If the missing report count for TSN t is to be * 3) If the missing report count for TSN t is to be
* incremented according to [RFC2960] and * incremented according to [RFC2960] and
* [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set, * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set,
* then the sender MUST futher execute steps 3.1 and * then the sender MUST futher execute steps 3.1 and
* 3.2 to determine if the missing report count for * 3.2 to determine if the missing report count for
...@@ -251,8 +251,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -251,8 +251,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
chunk = list_entry(lchunk, struct sctp_chunk, chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list); transmitted_list);
/* Mark as part of a failed message. */ /* Mark as part of a failed message. */
chunk->msg->send_failed = 1; sctp_datamsg_fail(chunk, q->error);
/* Generate a SEND FAILED event. */
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} }
} }
...@@ -262,6 +261,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -262,6 +261,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
list_del(lchunk); list_del(lchunk);
chunk = list_entry(lchunk, struct sctp_chunk, chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list); transmitted_list);
sctp_datamsg_fail(chunk, q->error);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} }
...@@ -270,6 +270,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -270,6 +270,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
list_del(lchunk); list_del(lchunk);
chunk = list_entry(lchunk, struct sctp_chunk, chunk = list_entry(lchunk, struct sctp_chunk,
transmitted_list); transmitted_list);
sctp_datamsg_fail(chunk, q->error);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} }
...@@ -277,7 +278,7 @@ void sctp_outq_teardown(struct sctp_outq *q) ...@@ -277,7 +278,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
while ((chunk = sctp_outq_dequeue_data(q))) { while ((chunk = sctp_outq_dequeue_data(q))) {
/* Mark as send failure. */ /* Mark as send failure. */
chunk->msg->send_failed = 1; sctp_datamsg_fail(chunk, q->error);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
} }
...@@ -800,27 +801,25 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -800,27 +801,25 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
*/ */
if (chunk->sinfo.sinfo_stream >= if (chunk->sinfo.sinfo_stream >=
asoc->c.sinit_num_ostreams) { asoc->c.sinit_num_ostreams) {
/* Mark as failed send. */
chunk->msg->send_failed = 1;
chunk->msg->send_error = SCTP_ERROR_INV_STRM;
/* Free the chunk. */ /* Mark as s failed send. */
sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM);
sctp_chunk_free(chunk); sctp_chunk_free(chunk);
continue; continue;
} }
/* Now do delayed assignment of SSN. This will /* Has this chunk expired? */
* probably change again when we start supporting if (sctp_datamsg_expires(chunk)) {
* large (> approximately 2^16) size messages. sctp_datamsg_fail(chunk, 0);
*/ sctp_chunk_free(chunk);
sctp_chunk_assign_ssn(chunk); continue;
}
/* If there is a specified transport, use it. /* If there is a specified transport, use it.
* Otherwise, we want to use the active path. * Otherwise, we want to use the active path.
*/ */
new_transport = chunk->transport; new_transport = chunk->transport;
if (new_transport == NULL || if (!new_transport || !new_transport->active)
!new_transport->active)
new_transport = asoc->peer.active_path; new_transport = asoc->peer.active_path;
/* Change packets if necessary. */ /* Change packets if necessary. */
...@@ -1024,10 +1023,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) ...@@ -1024,10 +1023,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
/* /*
* SFR-CACC algorithm: * SFR-CACC algorithm:
* On receipt of a SACK the sender SHOULD execute the * On receipt of a SACK the sender SHOULD execute the
* following statements. * following statements.
* *
* 1) If the cumulative ack in the SACK passes next tsn_at_change * 1) If the cumulative ack in the SACK passes next tsn_at_change
* on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be
* cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for
* all destinations. * all destinations.
...@@ -1041,7 +1040,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) ...@@ -1041,7 +1040,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
} }
} }
/* /*
* SFR-CACC algorithm: * SFR-CACC algorithm:
* 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE
* is set the receiver of the SACK MUST take the following actions: * is set the receiver of the SACK MUST take the following actions:
...@@ -1087,7 +1086,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) ...@@ -1087,7 +1086,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
transport, sack, highest_new_tsn); transport, sack, highest_new_tsn);
/* /*
* SFR-CACC algorithm: * SFR-CACC algorithm:
* C) Let count_of_newacks be the number of * C) Let count_of_newacks be the number of
* destinations for which cacc_saw_newack is set. * destinations for which cacc_saw_newack is set.
*/ */
if (transport->cacc.cacc_saw_newack) if (transport->cacc.cacc_saw_newack)
...@@ -1097,7 +1096,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) ...@@ -1097,7 +1096,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
list_for_each(pos, transport_list) { list_for_each(pos, transport_list) {
transport = list_entry(pos, struct sctp_transport, transport = list_entry(pos, struct sctp_transport,
transports); transports);
sctp_mark_missing(q, &transport->transmitted, transport, sctp_mark_missing(q, &transport->transmitted, transport,
highest_new_tsn, count_of_newacks); highest_new_tsn, count_of_newacks);
} }
...@@ -1275,8 +1274,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, ...@@ -1275,8 +1274,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
* the destination that the TSN was * the destination that the TSN was
* sent to. * sent to.
*/ */
if (transport && if (transport &&
sack->num_gap_ack_blocks && sack->num_gap_ack_blocks &&
q->asoc->peer.primary_path->cacc. q->asoc->peer.primary_path->cacc.
changeover_active) changeover_active)
transport->cacc.cacc_saw_newack transport->cacc.cacc_saw_newack
...@@ -1529,12 +1528,12 @@ static void sctp_mark_missing(struct sctp_outq *q, ...@@ -1529,12 +1528,12 @@ static void sctp_mark_missing(struct sctp_outq *q,
TSN_lt(tsn, highest_new_tsn_in_sack)) { TSN_lt(tsn, highest_new_tsn_in_sack)) {
/* SFR-CACC may require us to skip marking /* SFR-CACC may require us to skip marking
* this chunk as missing. * this chunk as missing.
*/ */
if (!transport || !sctp_cacc_skip(primary, transport, if (!transport || !sctp_cacc_skip(primary, transport,
count_of_newacks, tsn)) { count_of_newacks, tsn)) {
chunk->tsn_missing_report++; chunk->tsn_missing_report++;
SCTP_DEBUG_PRINTK( SCTP_DEBUG_PRINTK(
"%s: TSN 0x%x missing counter: %d\n", "%s: TSN 0x%x missing counter: %d\n",
__FUNCTION__, tsn, __FUNCTION__, tsn,
......
...@@ -987,7 +987,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, ...@@ -987,7 +987,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
retval->has_tsn = 0; retval->has_tsn = 0;
retval->has_ssn = 0; retval->has_ssn = 0;
retval->rtt_in_progress = 0; retval->rtt_in_progress = 0;
retval->sent_at = jiffies; retval->sent_at = 0;
retval->singleton = 1; retval->singleton = 1;
retval->end_of_packet = 0; retval->end_of_packet = 0;
retval->ecn_ce_done = 0; retval->ecn_ce_done = 0;
......
...@@ -2372,7 +2372,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, ...@@ -2372,7 +2372,8 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
* PMTU. In cases, such as loopback, this might be a rather * PMTU. In cases, such as loopback, this might be a rather
* large spill over. * large spill over.
*/ */
if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) { if (!asoc->rwnd || asoc->rwnd_over ||
(datalen > asoc->rwnd + asoc->frag_point)) {
/* If this is the next TSN, consider reneging to make /* If this is the next TSN, consider reneging to make
* room. Note: Playing nice with a confused sender. A * room. Note: Playing nice with a confused sender. A
......
...@@ -782,7 +782,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -782,7 +782,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
long timeo; long timeo;
__u16 sinfo_flags = 0; __u16 sinfo_flags = 0;
struct sctp_datamsg *datamsg; struct sctp_datamsg *datamsg;
struct list_head *pos, *temp; struct list_head *pos;
int msg_flags = msg->msg_flags; int msg_flags = msg->msg_flags;
SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n", SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n",
...@@ -1089,9 +1089,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1089,9 +1089,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
} }
/* Now send the (possibly) fragmented message. */ /* Now send the (possibly) fragmented message. */
list_for_each_safe(pos, temp, &datamsg->chunks) { list_for_each(pos, &datamsg->chunks) {
chunk = list_entry(pos, struct sctp_chunk, frag_list); chunk = list_entry(pos, struct sctp_chunk, frag_list);
list_del_init(pos);
sctp_datamsg_track(chunk); sctp_datamsg_track(chunk);
/* Do accounting for the write space. */ /* Do accounting for the write space. */
...@@ -1099,7 +1098,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1099,7 +1098,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
chunk->transport = chunk_tp; chunk->transport = chunk_tp;
/* Send it to the lower layers. */ /* Send it to the lower layers. Note: all chunks
* must either fail or succeed. The lower layer
* works that way today. Keep it that way or this
* breaks.
*/
err = sctp_primitive_SEND(asoc, chunk); err = sctp_primitive_SEND(asoc, chunk);
/* Did the lower layer accept the chunk? */ /* Did the lower layer accept the chunk? */
if (err) if (err)
...@@ -1108,7 +1111,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1108,7 +1111,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
} }
sctp_datamsg_free(datamsg); sctp_datamsg_free(datamsg);
if (err) if (err)
goto out_free; goto out_free;
else else
err = msg_len; err = msg_len;
...@@ -3755,7 +3758,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, ...@@ -3755,7 +3758,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
/* If the association on the newsk is already closed before accept() /* If the association on the newsk is already closed before accept()
* is called, set RCV_SHUTDOWN flag. * is called, set RCV_SHUTDOWN flag.
*/ */
if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP))
newsk->shutdown |= RCV_SHUTDOWN; newsk->shutdown |= RCV_SHUTDOWN;
......
...@@ -425,6 +425,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -425,6 +425,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
struct sctp_send_failed *ssf; struct sctp_send_failed *ssf;
struct sk_buff *skb; struct sk_buff *skb;
/* Pull off any padding. */
int len = ntohs(chunk->chunk_hdr->length);
/* Make skb with more room so we can prepend notification. */ /* Make skb with more room so we can prepend notification. */
skb = skb_copy_expand(chunk->skb, skb = skb_copy_expand(chunk->skb,
sizeof(struct sctp_send_failed), /* headroom */ sizeof(struct sctp_send_failed), /* headroom */
...@@ -434,7 +437,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -434,7 +437,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
goto fail; goto fail;
/* Pull off the common chunk header and DATA header. */ /* Pull off the common chunk header and DATA header. */
skb_pull(skb, sizeof(sctp_data_chunk_t)); skb_pull(skb, sizeof(struct sctp_data_chunk));
len -= sizeof(struct sctp_data_chunk);
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb); event = sctp_skb2event(skb);
...@@ -475,7 +479,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -475,7 +479,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
* This field is the total length of the notification data, including * This field is the total length of the notification data, including
* the notification header. * the notification header.
*/ */
ssf->ssf_length = skb->len; ssf->ssf_length = sizeof(struct sctp_send_failed) + len;
skb_trim(skb, ssf->ssf_length);
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
...@@ -496,6 +501,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed( ...@@ -496,6 +501,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
*/ */
memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo)); memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
/* Per TSVWG discussion with Randy. Allow the application to
* ressemble a fragmented message.
*/
ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
* *
......
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