* [PATCH] Replace timetolive with pr_policy and pr_value
@ 2008-12-03 1:59 Horacio Sanson
2008-12-03 7:15 ` Horacio Sanson
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Horacio Sanson @ 2008-12-03 1:59 UTC (permalink / raw)
To: linux-sctp
[-- Attachment #1: Type: text/plain, Size: 775 bytes --]
Updated lksctp-dev and lksctp-tools to follow the most recent
sctpsocket draft 18 by replacing all instances of timetolive from the
sctp_sndrcvinfo structure with the sinfo_pr_policy and sinfo_pr_value
fields. I ran the tests in lksctp-tools and to my surprise they all
pass.
This is the first time I have put my dirty hands on the holy kernel
source so please expect to find mistakes all over the place. I also
tried to implement the SCTP_PR_SCTP_RTX policy based on the FreeBSD
implementation but I am not sure were exactly I should decrement the
number of retransmission counter. I do it in the
sctp_retransmit_mark() method but not really sure if is correct and I
am not good enough to make a test for it. Some help here would be
greatly appreciated.
regards,
Horacio
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: lksctp-dev-pr-src.diff --]
[-- Type: text/x-diff; name=lksctp-dev-pr-src.diff, Size: 7964 bytes --]
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f4b2304..c178139 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->default_ppid = sp->default_ppid;
asoc->default_flags = sp->default_flags;
asoc->default_context = sp->default_context;
- asoc->default_timetolive = sp->default_timetolive;
+ asoc->default_pr_policy = sp->default_pr_policy;
+ asoc->default_pr_value = sp->default_pr_value;
asoc->default_rcv_context = sp->default_rcv_context;
/* AUTH related initializations */
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 1748ef9..e98cc5b 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
atomic_set(&msg->refcnt, 1);
msg->send_failed = 0;
msg->send_error = 0;
- msg->can_abandon = 0;
+ msg->expires_policy = SCTP_PR_SCTP_NONE;
msg->expires_at = 0;
INIT_LIST_HEAD(&msg->chunks);
}
@@ -170,13 +170,26 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
/* Note: Calculate this outside of the loop, so that all fragments
* have the same expiration.
*/
- if (sinfo->sinfo_timetolive) {
- /* sinfo_timetolive is in milliseconds */
- msg->expires_at = jiffies +
- msecs_to_jiffies(sinfo->sinfo_timetolive);
- msg->can_abandon = 1;
- SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
- __func__, msg, msg->expires_at, jiffies);
+
+ msg->expires_policy = sinfo->sinfo_pr_policy;
+
+ if(msg->expires_policy) {
+ switch(msg->expires_policy) {
+ case SCTP_PR_SCTP_TTL:
+ /* sinfo_timetolive is in milliseconds */
+ msg->expires_at = jiffies +
+ msecs_to_jiffies(sinfo->sinfo_pr_value);
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
+ __func__, msg, msg->expires_at, jiffies);
+ break;
+ case SCTP_PR_SCTP_BUF:
+ break;
+ case SCTP_PR_SCTP_RTX:
+ msg->expires_at = sinfo->sinfo_pr_value;
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_after: %ld retransmissions \n",
+ __func__, msg, msg->expires_at);
+ break;
+ }
}
max = asoc->frag_point;
@@ -291,11 +304,20 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
{
struct sctp_datamsg *msg = chunk->msg;
- if (!msg->can_abandon)
+ if (!msg->expires_policy)
return 0;
- if (time_after(jiffies, msg->expires_at))
- return 1;
+ switch(msg->expires_policy) {
+ case SCTP_PR_SCTP_TTL:
+ if (time_after(jiffies, msg->expires_at))
+ return 1;
+ case SCTP_PR_SCTP_BUF:
+ /* TODO: Implement this */
+ return 0;
+ case SCTP_PR_SCTP_RTX:
+ if(msg->expires_at <= 0)
+ return 1;
+ }
return 0;
}
diff --git a/net/sctp/output.c b/net/sctp/output.c
index c3f417f..b344a9d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
asoc->peer.rwnd = rwnd;
/* Has been accepted for transmission. */
if (!asoc->peer.prsctp_capable)
- chunk->msg->can_abandon = 0;
+ chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
finish:
return retval;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 247ebc9..cce5bab 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -462,6 +462,13 @@ void sctp_retransmit_mark(struct sctp_outq *q,
transport->rto_pending = 0;
}
+ /* If the sinfo_pr_policy is SCTP_PR_SCTP_RTX we have
+ * to decrement the chunk expire_at value
+ */
+ if(chunk->msg->expires_policy == SCTP_PR_SCTP_RTX)
+ chunk->msg->expires_at--;
+
+
/* Move the chunk to the retransmit queue. The chunks
* on the retransmit queue are always kept in order.
*/
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1b9045..1504e28 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
default_sinfo.sinfo_flags = asoc->default_flags;
default_sinfo.sinfo_ppid = asoc->default_ppid;
default_sinfo.sinfo_context = asoc->default_context;
- default_sinfo.sinfo_timetolive = asoc->default_timetolive;
+ default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
+ default_sinfo.sinfo_pr_value = asoc->default_pr_value;
default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
sinfo = &default_sinfo;
}
@@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
+ * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*/
static int sctp_setsockopt_default_send_param(struct sock *sk,
@@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
asoc->default_flags = info.sinfo_flags;
asoc->default_ppid = info.sinfo_ppid;
asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_pr_policy = info.sinfo_pr_policy;
+ asoc->default_pr_value = info.sinfo_pr_value;
} else {
sp->default_stream = info.sinfo_stream;
sp->default_flags = info.sinfo_flags;
sp->default_ppid = info.sinfo_ppid;
sp->default_context = info.sinfo_context;
- sp->default_timetolive = info.sinfo_timetolive;
+ sp->default_pr_policy = info.sinfo_pr_policy;
+ sp->default_pr_value = info.sinfo_pr_value;
}
return 0;
@@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->default_ppid = 0;
sp->default_flags = 0;
sp->default_context = 0;
- sp->default_timetolive = 0;
+ sp->default_pr_policy = 0;
+ sp->default_pr_value = 0;
sp->default_rcv_context = 0;
sp->max_burst = sctp_max_burst;
@@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
+ * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*
* For getsockopt, it get the default sctp_sndrcvinfo structure.
@@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
info.sinfo_flags = asoc->default_flags;
info.sinfo_ppid = asoc->default_ppid;
info.sinfo_context = asoc->default_context;
- info.sinfo_timetolive = asoc->default_timetolive;
+ info.sinfo_pr_policy = asoc->default_pr_policy;
+ info.sinfo_pr_value = asoc->default_pr_value;
} else {
info.sinfo_stream = sp->default_stream;
info.sinfo_flags = sp->default_flags;
info.sinfo_ppid = sp->default_ppid;
info.sinfo_context = sp->default_context;
- info.sinfo_timetolive = sp->default_timetolive;
+ info.sinfo_pr_policy = sp->default_pr_policy;
+ info.sinfo_pr_value = sp->default_pr_value;
}
if (put_user(len, optlen))
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 5f186ca..2c6f111 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
sinfo.sinfo_context = event->asoc->default_rcv_context;
/* These fields are not used while receiving. */
- sinfo.sinfo_timetolive = 0;
+ sinfo.sinfo_pr_policy = 0;
+ sinfo.sinfo_pr_value = 0;
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: lksctp-dev-pr-inc.diff --]
[-- Type: text/x-diff; name=lksctp-dev-pr-inc.diff, Size: 5665 bytes --]
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 9661d7b..ffda4c5 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -208,7 +208,7 @@ extern struct sctp_globals {
/* Lock that protects the local_addr_list writers */
spinlock_t addr_list_lock;
-
+
/* Flag to indicate if addip is enabled. */
int addip_enable;
int addip_noauth_enable;
@@ -282,7 +282,8 @@ struct sctp_sock {
__u32 default_ppid;
__u16 default_flags;
__u32 default_context;
- __u32 default_timetolive;
+ __u16 default_pr_policy;
+ __u32 default_pr_value;
__u32 default_rcv_context;
int max_burst;
@@ -390,7 +391,7 @@ struct sctp_cookie {
/* This holds the originating address of the INIT packet. */
union sctp_addr peer_addr;
- /* IG Section 2.35.3
+ /* IG Section 2.35.3
* Include the source port of the INIT-ACK
*/
__u16 my_port;
@@ -398,7 +399,7 @@ struct sctp_cookie {
__u8 prsctp_capable;
/* Padding for future use */
- __u8 padding;
+ __u8 padding;
__u32 adaptation_ind;
@@ -512,12 +513,12 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
}
/* Skip over this ssn and all below. */
-static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
+static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
__u16 ssn)
{
stream->ssn[id] = ssn+1;
}
-
+
/*
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
@@ -575,7 +576,7 @@ struct sctp_af {
union sctp_addr_param *,
__be16 port, int iif);
int (*to_addr_param) (const union sctp_addr *,
- union sctp_addr_param *);
+ union sctp_addr_param *);
int (*addr_valid) (union sctp_addr *,
struct sctp_sock *,
const struct sk_buff *);
@@ -626,13 +627,15 @@ struct sctp_datamsg {
struct list_head track;
/* Reference counting. */
atomic_t refcnt;
+
+ /* Policy used to determine expired messages */
+ unsigned long expires_policy;
/* When is this message no longer interesting to the peer? */
unsigned long expires_at;
/* Did the messenge fail to send? */
int send_error;
char send_failed;
/* Control whether chunks from this message can be abandoned. */
- char can_abandon;
};
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
@@ -1339,7 +1342,7 @@ struct sctp_endpoint {
* on every receive.
*/
__u8 *digest;
-
+
/* sendbuf acct. policy. */
__u32 sndbuf_policy;
@@ -1759,9 +1762,10 @@ struct sctp_association {
/* Default send parameters. */
__u16 default_stream;
__u16 default_flags;
+ __u16 default_pr_policy;
__u32 default_ppid;
__u32 default_context;
- __u32 default_timetolive;
+ __u32 default_pr_value;
/* Default receive parameters */
__u32 default_rcv_context;
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index f205b10..c857cc5 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -71,7 +71,7 @@ enum sctp_optname {
#define SCTP_NODELAY SCTP_NODELAY
SCTP_AUTOCLOSE,
#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
- SCTP_SET_PEER_PRIMARY_ADDR,
+ SCTP_SET_PEER_PRIMARY_ADDR,
#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
SCTP_PRIMARY_ADDR,
#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
@@ -120,7 +120,7 @@ enum sctp_optname {
#define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
- /* Internal Socket Options. Some of the sctp library functions are
+ /* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options.
*/
SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
@@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
__u16 sinfo_stream;
__u16 sinfo_ssn;
__u16 sinfo_flags;
+ __u16 sinfo_pr_policy;
__u32 sinfo_ppid;
__u32 sinfo_context;
- __u32 sinfo_timetolive;
+ __u32 sinfo_pr_value;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
@@ -202,9 +203,22 @@ enum sctp_sinfo_flags {
SCTP_UNORDERED = 1, /* Send/receive message unordered. */
SCTP_ADDR_OVER = 2, /* Override the primary destination. */
SCTP_ABORT=4, /* Send an ABORT message to the peer. */
- SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
};
+/*
+ * sinfo_pr_policy: 16 bits (unsigned integer)
+ *
+ * This field may contain the partial reliability used to
+ * send the message.
+ */
+
+enum sctp_sinfo_pr_policy {
+ SCTP_PR_SCTP_NONE = 0, /* Reliable transmission */
+ SCTP_PR_SCTP_TTL = 1, /* Timed partial reliability */
+ SCTP_PR_SCTP_BUF = 2, /* Buffer parital reliability (EXPERIMENTAL) */
+ SCTP_PR_SCTP_RTX = 3, /* Retransmis partial reliability (EXPERIMENTAL) */
+};
typedef union {
__u8 raw;
@@ -479,7 +493,7 @@ typedef enum sctp_sn_error {
*
* The protocol parameters used to initialize and bound retransmission
* timeout (RTO) are tunable. See [SCTP] for more information on how
- * these parameters are used in RTO calculation.
+ * these parameters are used in RTO calculation.
*/
struct sctp_rtoinfo {
sctp_assoc_t srto_assoc_id;
@@ -717,9 +731,9 @@ struct sctp_authchunks {
/*
* 8.3, 8.5 get all peer/local addresses in an association.
- * This parameter struct is used by SCTP_GET_PEER_ADDRS and
+ * This parameter struct is used by SCTP_GET_PEER_ADDRS and
* SCTP_GET_LOCAL_ADDRS socket options used internally to implement
- * sctp_getpaddrs() and sctp_getladdrs() API.
+ * sctp_getpaddrs() and sctp_getladdrs() API.
*/
struct sctp_getaddrs_old {
sctp_assoc_t assoc_id;
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: lksctp-tools-pr.diff --]
[-- Type: text/x-diff; name=lksctp-tools-pr.diff, Size: 6291 bytes --]
diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
index c275e45..d5e26d5 100644
--- a/src/func_tests/test_sctp_sendrecvmsg.c
+++ b/src/func_tests/test_sctp_sendrecvmsg.c
@@ -335,7 +335,8 @@ int main(int argc, char *argv[])
snd_sinfo.sinfo_ppid = rand();
snd_sinfo.sinfo_flags = 0;
snd_sinfo.sinfo_stream = 2;
- snd_sinfo.sinfo_timetolive = 0;
+ snd_sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ snd_sinfo.sinfo_pr_value = 0;
snd_sinfo.sinfo_assoc_id = associd1;
test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
MSG_NOSIGNAL);
diff --git a/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
index d9bdf1b..dc66722 100644
--- a/src/func_tests/test_timetolive.c
+++ b/src/func_tests/test_timetolive.c
@@ -39,14 +39,14 @@
/*
* This is a basic functional test for the SCTP kernel
- * implementation of sndrcvinfo.sinfo_timetolive.
+ * implementation of sndrcvinfo.sinfo_pr_value.
*
* 1) Create two sockets, the listening socket sets its RECVBUF small
* 2) Create a connection. Send enough data to the non-reading listener
* to fill the RCVBUF.
- * 5) Set sinfo_timetolive on a message and send.
- * 6) Disable sinfo_timetolive on a message and send.
- * 7) Wait sinfo_timetolive.
+ * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
+ * 6) Disable sinfo_pr_value on a message and send.
+ * 7) Wait sinfo_pr_value time.
* 8) Read out all the data at the receiver.
* 9) Make sure timed out message did not make it.
* 10) Make sure that the message with no timeout makes it to the receiver.
@@ -288,7 +288,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 0;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
gstatus.sstat_rwnd+RWND_SLOP);
@@ -300,7 +301,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 2000;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ sinfo->sinfo_pr_value = 2000;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
tst_resm(TPASS, "Send a message with timeout");
@@ -313,7 +315,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 0;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
tst_resm(TPASS, "Send a message with no timeout");
@@ -328,7 +331,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 2000;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ sinfo->sinfo_pr_value = 2000;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
tst_resm(TPASS, "Send a fragmented message with timeout");
diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h
index ae557a5..53454db 100644
--- a/src/include/netinet/sctp.h
+++ b/src/include/netinet/sctp.h
@@ -184,9 +184,10 @@ struct sctp_sndrcvinfo {
__u16 sinfo_stream;
__u16 sinfo_ssn;
__u16 sinfo_flags;
+ __u16 sinfo_pr_policy;
__u32 sinfo_ppid;
__u32 sinfo_context;
- __u32 sinfo_timetolive;
+ __u32 sinfo_pr_value;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
@@ -206,6 +207,17 @@ enum sctp_sinfo_flags {
SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
};
+/*
+ * sinfo_pr_policy: 16 bits (unsigned integer)
+ *
+ */
+
+enum sctp_sinfo_pr_policy {
+ SCTP_PR_SCTP_NONE = 0, /* Reliable transmission */
+ SCTP_PR_SCTP_TTL = 1, /* Timed partial reliable */
+ SCTP_PR_SCTP_BUF = 2, /* Buffer parital reliable */
+ SCTP_PR_SCTP_RTX = 3, /* Retransmist partial reliable */
+};
typedef union {
__u8 raw;
@@ -816,7 +828,7 @@ int sctp_freeladdrs(struct sockaddr *addrs);
*/
int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
socklen_t tolen, uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive, uint32_t context);
+ uint16_t stream_no, uint32_t pr_value, uint32_t context);
/* This library function assist the user with sending a message without
* dealing directly with the CMSG header.
diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
index 1de592d..2b6b46e 100644
--- a/src/lib/sendmsg.c
+++ b/src/lib/sendmsg.c
@@ -31,7 +31,7 @@
int
sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
socklen_t tolen, uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive, uint32_t context)
+ uint16_t stream_no, uint32_t pr_value, uint32_t context)
{
struct msghdr outmsg;
struct iovec iov;
@@ -61,9 +61,16 @@ sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
sinfo->sinfo_ppid = ppid;
sinfo->sinfo_flags = flags;
sinfo->sinfo_stream = stream_no;
- sinfo->sinfo_timetolive = timetolive;
sinfo->sinfo_context = context;
+ /* This is needed for the test_sctp_sendrecv to pass */
+ sinfo->sinfo_pr_value = pr_value;
+ if(sinfo->sinfo_pr_value > 0) {
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ } else {
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ }
+
return sendmsg(s, &outmsg, 0);
}
diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
index 347c91b..0afbc36 100644
--- a/src/testlib/sctputil.h
+++ b/src/testlib/sctputil.h
@@ -270,11 +270,11 @@ static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
struct sockaddr *to, socklen_t tolen,
uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive,
+ uint16_t stream_no, uint32_t pr_value,
uint32_t context)
{
int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
- timetolive, context);
+ pr_value, context);
if (len != error)
tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
error, errno);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] Replace timetolive with pr_policy and pr_value
2008-12-03 1:59 [PATCH] Replace timetolive with pr_policy and pr_value Horacio Sanson
@ 2008-12-03 7:15 ` Horacio Sanson
2008-12-15 9:56 ` Horacio Sanson
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Horacio Sanson @ 2008-12-03 7:15 UTC (permalink / raw)
To: linux-sctp
[-- Attachment #1: Type: text/plain, Size: 2799 bytes --]
Please ignore my previous patch set and check these instead...
Testing my own patch I realized that there is no way to set what PR
policy to use when using the sctp_sendmsg() call. Following examples
from FreeBSD SCTP implementation I modified my patch to allow setting
the PR policy as part of the flags passed to the call. For example to
send a message with timed reliability and unordered delivery we can
use:
sctp_sendmsg(sd, msg, len, to, tolen, rand(),
SCTP_UNORDERED | SCTP_PR_SCTP_TTL, 2000, 0);
The scptsocket api draft says nothing about this but makes sense that
if we can set a pr_value we should be also be able to set the PR
policy too. All tests passed and got a nice "Hoody hoo!" message at
the end of both v4test and v6test tests.
I have some questions regarding my changes as I am new to Kernel development:
Seems to me that values assigned to SCTP_PR_SCTP_TTL, SCTP_PR_SCTP_RTX, etc..
are irrelevant to the receiver so we can assign any values to them that not
necessarily coincide with their values assigned in other
implementations. Still I made my best to make these values coincide
with FreeBSD implementation. What values shall I assign to these
variables??
I had to remove the sinfo_flags validation from the
sctp_msghdr_parse() call in socket.c file. Any tips on how to enable
it again but considering the additional PR policy flags is
appreciated.
Again I am not sure where is the best place to decrement the number of
retransmission when using the experimental SCTP_PR_SCTP_RTX policy.
And some guidance on how to implement a test for this functionality is
welcome.
I used these commands to create the diff files... not sure if it is
the correct way:
cd lksctp-dev
git diff -p origin... include/net/sctp > lksctp-dev-inc-pr.diff
git diff -p origin... net/sctp > lksctp-dev-src-pr.diff
cd lksctp-tools
git diff -p origin... > lksctp-tools-pr.diff
regards,
Horacio
On Wed, Dec 3, 2008 at 10:59 AM, Horacio Sanson <hsanson@gmail.com> wrote:
> Updated lksctp-dev and lksctp-tools to follow the most recent
> sctpsocket draft 18 by replacing all instances of timetolive from the
> sctp_sndrcvinfo structure with the sinfo_pr_policy and sinfo_pr_value
> fields. I ran the tests in lksctp-tools and to my surprise they all
> pass.
>
> This is the first time I have put my dirty hands on the holy kernel
> source so please expect to find mistakes all over the place. I also
> tried to implement the SCTP_PR_SCTP_RTX policy based on the FreeBSD
> implementation but I am not sure were exactly I should decrement the
> number of retransmission counter. I do it in the
> sctp_retransmit_mark() method but not really sure if is correct and I
> am not good enough to make a test for it. Some help here would be
> greatly appreciated.
>
>
> regards,
> Horacio
>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: lksctp-dev-inc-pr.diff --]
[-- Type: text/x-diff; name=lksctp-dev-inc-pr.diff, Size: 5948 bytes --]
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 9661d7b..ffda4c5 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -208,7 +208,7 @@ extern struct sctp_globals {
/* Lock that protects the local_addr_list writers */
spinlock_t addr_list_lock;
-
+
/* Flag to indicate if addip is enabled. */
int addip_enable;
int addip_noauth_enable;
@@ -282,7 +282,8 @@ struct sctp_sock {
__u32 default_ppid;
__u16 default_flags;
__u32 default_context;
- __u32 default_timetolive;
+ __u16 default_pr_policy;
+ __u32 default_pr_value;
__u32 default_rcv_context;
int max_burst;
@@ -390,7 +391,7 @@ struct sctp_cookie {
/* This holds the originating address of the INIT packet. */
union sctp_addr peer_addr;
- /* IG Section 2.35.3
+ /* IG Section 2.35.3
* Include the source port of the INIT-ACK
*/
__u16 my_port;
@@ -398,7 +399,7 @@ struct sctp_cookie {
__u8 prsctp_capable;
/* Padding for future use */
- __u8 padding;
+ __u8 padding;
__u32 adaptation_ind;
@@ -512,12 +513,12 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
}
/* Skip over this ssn and all below. */
-static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
+static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
__u16 ssn)
{
stream->ssn[id] = ssn+1;
}
-
+
/*
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
@@ -575,7 +576,7 @@ struct sctp_af {
union sctp_addr_param *,
__be16 port, int iif);
int (*to_addr_param) (const union sctp_addr *,
- union sctp_addr_param *);
+ union sctp_addr_param *);
int (*addr_valid) (union sctp_addr *,
struct sctp_sock *,
const struct sk_buff *);
@@ -626,13 +627,15 @@ struct sctp_datamsg {
struct list_head track;
/* Reference counting. */
atomic_t refcnt;
+
+ /* Policy used to determine expired messages */
+ unsigned long expires_policy;
/* When is this message no longer interesting to the peer? */
unsigned long expires_at;
/* Did the messenge fail to send? */
int send_error;
char send_failed;
/* Control whether chunks from this message can be abandoned. */
- char can_abandon;
};
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
@@ -1339,7 +1342,7 @@ struct sctp_endpoint {
* on every receive.
*/
__u8 *digest;
-
+
/* sendbuf acct. policy. */
__u32 sndbuf_policy;
@@ -1759,9 +1762,10 @@ struct sctp_association {
/* Default send parameters. */
__u16 default_stream;
__u16 default_flags;
+ __u16 default_pr_policy;
__u32 default_ppid;
__u32 default_context;
- __u32 default_timetolive;
+ __u32 default_pr_value;
/* Default receive parameters */
__u32 default_rcv_context;
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index f205b10..74c0aba 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -71,7 +71,7 @@ enum sctp_optname {
#define SCTP_NODELAY SCTP_NODELAY
SCTP_AUTOCLOSE,
#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
- SCTP_SET_PEER_PRIMARY_ADDR,
+ SCTP_SET_PEER_PRIMARY_ADDR,
#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
SCTP_PRIMARY_ADDR,
#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
@@ -120,7 +120,7 @@ enum sctp_optname {
#define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
- /* Internal Socket Options. Some of the sctp library functions are
+ /* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options.
*/
SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
@@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
__u16 sinfo_stream;
__u16 sinfo_ssn;
__u16 sinfo_flags;
+ __u16 sinfo_pr_policy;
__u32 sinfo_ppid;
__u32 sinfo_context;
- __u32 sinfo_timetolive;
+ __u32 sinfo_pr_value;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
@@ -199,12 +200,25 @@ struct sctp_sndrcvinfo {
*/
enum sctp_sinfo_flags {
- SCTP_UNORDERED = 1, /* Send/receive message unordered. */
- SCTP_ADDR_OVER = 2, /* Override the primary destination. */
- SCTP_ABORT=4, /* Send an ABORT message to the peer. */
- SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. (0x0200) */
+ SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
+ SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
+ SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
};
+/*
+ * sinfo_pr_policy: 16 bits (unsigned integer)
+ *
+ * This field may contain the partial reliability used to
+ * send the message.
+ */
+
+enum sctp_sinfo_pr_policy {
+ SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
+ SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliability */
+ SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliability (EXPERIMENTAL) */
+ SCTP_PR_SCTP_RTX = 0x0003, /* Retransmis partial reliability (EXPERIMENTAL) */
+};
typedef union {
__u8 raw;
@@ -479,7 +493,7 @@ typedef enum sctp_sn_error {
*
* The protocol parameters used to initialize and bound retransmission
* timeout (RTO) are tunable. See [SCTP] for more information on how
- * these parameters are used in RTO calculation.
+ * these parameters are used in RTO calculation.
*/
struct sctp_rtoinfo {
sctp_assoc_t srto_assoc_id;
@@ -717,9 +731,9 @@ struct sctp_authchunks {
/*
* 8.3, 8.5 get all peer/local addresses in an association.
- * This parameter struct is used by SCTP_GET_PEER_ADDRS and
+ * This parameter struct is used by SCTP_GET_PEER_ADDRS and
* SCTP_GET_LOCAL_ADDRS socket options used internally to implement
- * sctp_getpaddrs() and sctp_getladdrs() API.
+ * sctp_getpaddrs() and sctp_getladdrs() API.
*/
struct sctp_getaddrs_old {
sctp_assoc_t assoc_id;
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: lksctp-dev-src-pr.diff --]
[-- Type: text/x-diff; name=lksctp-dev-src-pr.diff, Size: 8520 bytes --]
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f4b2304..c178139 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->default_ppid = sp->default_ppid;
asoc->default_flags = sp->default_flags;
asoc->default_context = sp->default_context;
- asoc->default_timetolive = sp->default_timetolive;
+ asoc->default_pr_policy = sp->default_pr_policy;
+ asoc->default_pr_value = sp->default_pr_value;
asoc->default_rcv_context = sp->default_rcv_context;
/* AUTH related initializations */
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 1748ef9..e98cc5b 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
atomic_set(&msg->refcnt, 1);
msg->send_failed = 0;
msg->send_error = 0;
- msg->can_abandon = 0;
+ msg->expires_policy = SCTP_PR_SCTP_NONE;
msg->expires_at = 0;
INIT_LIST_HEAD(&msg->chunks);
}
@@ -170,13 +170,26 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
/* Note: Calculate this outside of the loop, so that all fragments
* have the same expiration.
*/
- if (sinfo->sinfo_timetolive) {
- /* sinfo_timetolive is in milliseconds */
- msg->expires_at = jiffies +
- msecs_to_jiffies(sinfo->sinfo_timetolive);
- msg->can_abandon = 1;
- SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
- __func__, msg, msg->expires_at, jiffies);
+
+ msg->expires_policy = sinfo->sinfo_pr_policy;
+
+ if(msg->expires_policy) {
+ switch(msg->expires_policy) {
+ case SCTP_PR_SCTP_TTL:
+ /* sinfo_timetolive is in milliseconds */
+ msg->expires_at = jiffies +
+ msecs_to_jiffies(sinfo->sinfo_pr_value);
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
+ __func__, msg, msg->expires_at, jiffies);
+ break;
+ case SCTP_PR_SCTP_BUF:
+ break;
+ case SCTP_PR_SCTP_RTX:
+ msg->expires_at = sinfo->sinfo_pr_value;
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_after: %ld retransmissions \n",
+ __func__, msg, msg->expires_at);
+ break;
+ }
}
max = asoc->frag_point;
@@ -291,11 +304,20 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
{
struct sctp_datamsg *msg = chunk->msg;
- if (!msg->can_abandon)
+ if (!msg->expires_policy)
return 0;
- if (time_after(jiffies, msg->expires_at))
- return 1;
+ switch(msg->expires_policy) {
+ case SCTP_PR_SCTP_TTL:
+ if (time_after(jiffies, msg->expires_at))
+ return 1;
+ case SCTP_PR_SCTP_BUF:
+ /* TODO: Implement this */
+ return 0;
+ case SCTP_PR_SCTP_RTX:
+ if(msg->expires_at <= 0)
+ return 1;
+ }
return 0;
}
diff --git a/net/sctp/output.c b/net/sctp/output.c
index c3f417f..b344a9d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
asoc->peer.rwnd = rwnd;
/* Has been accepted for transmission. */
if (!asoc->peer.prsctp_capable)
- chunk->msg->can_abandon = 0;
+ chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
finish:
return retval;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 247ebc9..cce5bab 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -462,6 +462,13 @@ void sctp_retransmit_mark(struct sctp_outq *q,
transport->rto_pending = 0;
}
+ /* If the sinfo_pr_policy is SCTP_PR_SCTP_RTX we have
+ * to decrement the chunk expire_at value
+ */
+ if(chunk->msg->expires_policy == SCTP_PR_SCTP_RTX)
+ chunk->msg->expires_at--;
+
+
/* Move the chunk to the retransmit queue. The chunks
* on the retransmit queue are always kept in order.
*/
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1b9045..0dfc137 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
default_sinfo.sinfo_flags = asoc->default_flags;
default_sinfo.sinfo_ppid = asoc->default_ppid;
default_sinfo.sinfo_context = asoc->default_context;
- default_sinfo.sinfo_timetolive = asoc->default_timetolive;
+ default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
+ default_sinfo.sinfo_pr_value = asoc->default_pr_value;
default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
sinfo = &default_sinfo;
}
@@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
+ * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*/
static int sctp_setsockopt_default_send_param(struct sock *sk,
@@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
asoc->default_flags = info.sinfo_flags;
asoc->default_ppid = info.sinfo_ppid;
asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_pr_policy = info.sinfo_pr_policy;
+ asoc->default_pr_value = info.sinfo_pr_value;
} else {
sp->default_stream = info.sinfo_stream;
sp->default_flags = info.sinfo_flags;
sp->default_ppid = info.sinfo_ppid;
sp->default_context = info.sinfo_context;
- sp->default_timetolive = info.sinfo_timetolive;
+ sp->default_pr_policy = info.sinfo_pr_policy;
+ sp->default_pr_value = info.sinfo_pr_value;
}
return 0;
@@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->default_ppid = 0;
sp->default_flags = 0;
sp->default_context = 0;
- sp->default_timetolive = 0;
+ sp->default_pr_policy = 0;
+ sp->default_pr_value = 0;
sp->default_rcv_context = 0;
sp->max_burst = sctp_max_burst;
@@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
+ * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*
* For getsockopt, it get the default sctp_sndrcvinfo structure.
@@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
info.sinfo_flags = asoc->default_flags;
info.sinfo_ppid = asoc->default_ppid;
info.sinfo_context = asoc->default_context;
- info.sinfo_timetolive = asoc->default_timetolive;
+ info.sinfo_pr_policy = asoc->default_pr_policy;
+ info.sinfo_pr_value = asoc->default_pr_value;
} else {
info.sinfo_stream = sp->default_stream;
info.sinfo_flags = sp->default_flags;
info.sinfo_ppid = sp->default_ppid;
info.sinfo_context = sp->default_context;
- info.sinfo_timetolive = sp->default_timetolive;
+ info.sinfo_pr_policy = sp->default_pr_policy;
+ info.sinfo_pr_value = sp->default_pr_value;
}
if (put_user(len, optlen))
@@ -6107,10 +6113,17 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
(struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
/* Minimally, validate the sinfo_flags. */
+
+ /* TODO this validation does not work with the new
+ * SCTP_PR_SCTP_XXX flags
+ */
+
+ /*
if (cmsgs->info->sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
+ */
break;
default:
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 5f186ca..2c6f111 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
sinfo.sinfo_context = event->asoc->default_rcv_context;
/* These fields are not used while receiving. */
- sinfo.sinfo_timetolive = 0;
+ sinfo.sinfo_pr_policy = 0;
+ sinfo.sinfo_pr_value = 0;
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: lksctp-tools-pr.diff --]
[-- Type: text/x-diff; name=lksctp-tools-pr.diff, Size: 7817 bytes --]
diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
index c275e45..aaa56e9 100644
--- a/src/func_tests/test_sctp_sendrecvmsg.c
+++ b/src/func_tests/test_sctp_sendrecvmsg.c
@@ -243,7 +243,7 @@ int main(int argc, char *argv[])
/* Now send a message that will timeout. */
test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
(struct sockaddr *)&loop2, sizeof(loop2),
- ppid, 0, stream, 2000, 0);
+ ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
tst_resm(TPASS, "sctp_sendmsg with ttl");
@@ -259,7 +259,7 @@ int main(int argc, char *argv[])
ttlfrag[sizeof(ttlfrag)-1] = '\0';
test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
(struct sockaddr *)&loop2, sizeof(loop2),
- ppid, 0, stream, 2000, 0);
+ ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
@@ -335,7 +335,8 @@ int main(int argc, char *argv[])
snd_sinfo.sinfo_ppid = rand();
snd_sinfo.sinfo_flags = 0;
snd_sinfo.sinfo_stream = 2;
- snd_sinfo.sinfo_timetolive = 0;
+ snd_sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ snd_sinfo.sinfo_pr_value = 0;
snd_sinfo.sinfo_assoc_id = associd1;
test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
MSG_NOSIGNAL);
diff --git a/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
index d9bdf1b..dc66722 100644
--- a/src/func_tests/test_timetolive.c
+++ b/src/func_tests/test_timetolive.c
@@ -39,14 +39,14 @@
/*
* This is a basic functional test for the SCTP kernel
- * implementation of sndrcvinfo.sinfo_timetolive.
+ * implementation of sndrcvinfo.sinfo_pr_value.
*
* 1) Create two sockets, the listening socket sets its RECVBUF small
* 2) Create a connection. Send enough data to the non-reading listener
* to fill the RCVBUF.
- * 5) Set sinfo_timetolive on a message and send.
- * 6) Disable sinfo_timetolive on a message and send.
- * 7) Wait sinfo_timetolive.
+ * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
+ * 6) Disable sinfo_pr_value on a message and send.
+ * 7) Wait sinfo_pr_value time.
* 8) Read out all the data at the receiver.
* 9) Make sure timed out message did not make it.
* 10) Make sure that the message with no timeout makes it to the receiver.
@@ -288,7 +288,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 0;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
gstatus.sstat_rwnd+RWND_SLOP);
@@ -300,7 +301,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 2000;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ sinfo->sinfo_pr_value = 2000;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
tst_resm(TPASS, "Send a message with timeout");
@@ -313,7 +315,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 0;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
tst_resm(TPASS, "Send a message with no timeout");
@@ -328,7 +331,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 2000;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ sinfo->sinfo_pr_value = 2000;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
tst_resm(TPASS, "Send a fragmented message with timeout");
diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h
index ae557a5..5a6cea2 100644
--- a/src/include/netinet/sctp.h
+++ b/src/include/netinet/sctp.h
@@ -184,9 +184,10 @@ struct sctp_sndrcvinfo {
__u16 sinfo_stream;
__u16 sinfo_ssn;
__u16 sinfo_flags;
+ __u16 sinfo_pr_policy;
__u32 sinfo_ppid;
__u32 sinfo_context;
- __u32 sinfo_timetolive;
+ __u32 sinfo_pr_value;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
@@ -200,12 +201,25 @@ struct sctp_sndrcvinfo {
*/
enum sctp_sinfo_flags {
- SCTP_UNORDERED = 1, /* Send/receive message unordered. */
- SCTP_ADDR_OVER = 2, /* Override the primary destination. */
- SCTP_ABORT=4, /* Send an ABORT message to the peer. */
- SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
+ SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
+ SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
};
+/*
+ * sinfo_pr_policy: 16 bits (unsigned integer)
+ *
+ * This field may contain the partial reliability used to
+ * send the message.
+ */
+
+enum sctp_sinfo_pr_policy {
+ SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
+ SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliable */
+ SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliable */
+ SCTP_PR_SCTP_RTX = 0x0003, /* Retransmist partial reliable */
+};
typedef union {
__u8 raw;
@@ -816,7 +830,7 @@ int sctp_freeladdrs(struct sockaddr *addrs);
*/
int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
socklen_t tolen, uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive, uint32_t context);
+ uint16_t stream_no, uint32_t pr_value, uint32_t context);
/* This library function assist the user with sending a message without
* dealing directly with the CMSG header.
diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
index 1de592d..a674646 100644
--- a/src/lib/sendmsg.c
+++ b/src/lib/sendmsg.c
@@ -31,7 +31,7 @@
int
sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
socklen_t tolen, uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive, uint32_t context)
+ uint16_t stream_no, uint32_t pr_value, uint32_t context)
{
struct msghdr outmsg;
struct iovec iov;
@@ -61,9 +61,22 @@ sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
sinfo->sinfo_ppid = ppid;
sinfo->sinfo_flags = flags;
sinfo->sinfo_stream = stream_no;
- sinfo->sinfo_timetolive = timetolive;
sinfo->sinfo_context = context;
+ sinfo->sinfo_pr_policy = sinfo->sinfo_flags & 0xff;
+ sinfo->sinfo_pr_value = pr_value;
+
+ printf("sinfo_flags: %x sinfo_pr_policy: %d sinfo_pr_value: %d\n",
+ sinfo->sinfo_flags, sinfo->sinfo_pr_policy, sinfo->sinfo_pr_value);
+
+ /* If we get an invalid sinfo_pr_policy force it to
+ * SCTP_PR_SCTP_NONE or shall we better fail and set a
+ * EINVAL error??
+ */
+
+ if(sinfo->sinfo_pr_policy > SCTP_PR_SCTP_RTX)
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+
return sendmsg(s, &outmsg, 0);
}
diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
index 347c91b..0afbc36 100644
--- a/src/testlib/sctputil.h
+++ b/src/testlib/sctputil.h
@@ -270,11 +270,11 @@ static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
struct sockaddr *to, socklen_t tolen,
uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive,
+ uint16_t stream_no, uint32_t pr_value,
uint32_t context)
{
int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
- timetolive, context);
+ pr_value, context);
if (len != error)
tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
error, errno);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] Replace timetolive with pr_policy and pr_value
2008-12-03 1:59 [PATCH] Replace timetolive with pr_policy and pr_value Horacio Sanson
2008-12-03 7:15 ` Horacio Sanson
@ 2008-12-15 9:56 ` Horacio Sanson
2008-12-15 15:55 ` Vlad Yasevich
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Horacio Sanson @ 2008-12-15 9:56 UTC (permalink / raw)
To: linux-sctp
[-- Attachment #1: Type: text/plain, Size: 3384 bytes --]
I created a new patch set that fixes the SCTP_PR_SCTP_RTX partial
reliability that was not working and added a test program to test it.
Again all v4tests and v6tests pass including my own tests.
This includes the previous patches so the previous ones should be
ignored. But no one seems to be looking at my patches so I think there
should be no problems anyway :(.
comments appreciated,
Horacio
On Wed, Dec 3, 2008 at 4:15 PM, Horacio Sanson <hsanson@gmail.com> wrote:
> Please ignore my previous patch set and check these instead...
>
> Testing my own patch I realized that there is no way to set what PR
> policy to use when using the sctp_sendmsg() call. Following examples
> from FreeBSD SCTP implementation I modified my patch to allow setting
> the PR policy as part of the flags passed to the call. For example to
> send a message with timed reliability and unordered delivery we can
> use:
>
> sctp_sendmsg(sd, msg, len, to, tolen, rand(),
> SCTP_UNORDERED | SCTP_PR_SCTP_TTL, 2000, 0);
>
>
> The scptsocket api draft says nothing about this but makes sense that
> if we can set a pr_value we should be also be able to set the PR
> policy too. All tests passed and got a nice "Hoody hoo!" message at
> the end of both v4test and v6test tests.
>
> I have some questions regarding my changes as I am new to Kernel development:
>
> Seems to me that values assigned to SCTP_PR_SCTP_TTL, SCTP_PR_SCTP_RTX, etc..
> are irrelevant to the receiver so we can assign any values to them that not
> necessarily coincide with their values assigned in other
> implementations. Still I made my best to make these values coincide
> with FreeBSD implementation. What values shall I assign to these
> variables??
>
> I had to remove the sinfo_flags validation from the
> sctp_msghdr_parse() call in socket.c file. Any tips on how to enable
> it again but considering the additional PR policy flags is
> appreciated.
>
> Again I am not sure where is the best place to decrement the number of
> retransmission when using the experimental SCTP_PR_SCTP_RTX policy.
> And some guidance on how to implement a test for this functionality is
> welcome.
>
>
> I used these commands to create the diff files... not sure if it is
> the correct way:
>
> cd lksctp-dev
> git diff -p origin... include/net/sctp > lksctp-dev-inc-pr.diff
> git diff -p origin... net/sctp > lksctp-dev-src-pr.diff
>
> cd lksctp-tools
> git diff -p origin... > lksctp-tools-pr.diff
>
>
> regards,
> Horacio
>
> On Wed, Dec 3, 2008 at 10:59 AM, Horacio Sanson <hsanson@gmail.com> wrote:
>> Updated lksctp-dev and lksctp-tools to follow the most recent
>> sctpsocket draft 18 by replacing all instances of timetolive from the
>> sctp_sndrcvinfo structure with the sinfo_pr_policy and sinfo_pr_value
>> fields. I ran the tests in lksctp-tools and to my surprise they all
>> pass.
>>
>> This is the first time I have put my dirty hands on the holy kernel
>> source so please expect to find mistakes all over the place. I also
>> tried to implement the SCTP_PR_SCTP_RTX policy based on the FreeBSD
>> implementation but I am not sure were exactly I should decrement the
>> number of retransmission counter. I do it in the
>> sctp_retransmit_mark() method but not really sure if is correct and I
>> am not good enough to make a test for it. Some help here would be
>> greatly appreciated.
>>
>>
>> regards,
>> Horacio
>>
>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: lksctp-dev-inc-pr-20081216.diff --]
[-- Type: text/x-diff; name=lksctp-dev-inc-pr-20081216.diff, Size: 5948 bytes --]
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 9661d7b..ffda4c5 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -208,7 +208,7 @@ extern struct sctp_globals {
/* Lock that protects the local_addr_list writers */
spinlock_t addr_list_lock;
-
+
/* Flag to indicate if addip is enabled. */
int addip_enable;
int addip_noauth_enable;
@@ -282,7 +282,8 @@ struct sctp_sock {
__u32 default_ppid;
__u16 default_flags;
__u32 default_context;
- __u32 default_timetolive;
+ __u16 default_pr_policy;
+ __u32 default_pr_value;
__u32 default_rcv_context;
int max_burst;
@@ -390,7 +391,7 @@ struct sctp_cookie {
/* This holds the originating address of the INIT packet. */
union sctp_addr peer_addr;
- /* IG Section 2.35.3
+ /* IG Section 2.35.3
* Include the source port of the INIT-ACK
*/
__u16 my_port;
@@ -398,7 +399,7 @@ struct sctp_cookie {
__u8 prsctp_capable;
/* Padding for future use */
- __u8 padding;
+ __u8 padding;
__u32 adaptation_ind;
@@ -512,12 +513,12 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
}
/* Skip over this ssn and all below. */
-static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
+static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
__u16 ssn)
{
stream->ssn[id] = ssn+1;
}
-
+
/*
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
@@ -575,7 +576,7 @@ struct sctp_af {
union sctp_addr_param *,
__be16 port, int iif);
int (*to_addr_param) (const union sctp_addr *,
- union sctp_addr_param *);
+ union sctp_addr_param *);
int (*addr_valid) (union sctp_addr *,
struct sctp_sock *,
const struct sk_buff *);
@@ -626,13 +627,15 @@ struct sctp_datamsg {
struct list_head track;
/* Reference counting. */
atomic_t refcnt;
+
+ /* Policy used to determine expired messages */
+ unsigned long expires_policy;
/* When is this message no longer interesting to the peer? */
unsigned long expires_at;
/* Did the messenge fail to send? */
int send_error;
char send_failed;
/* Control whether chunks from this message can be abandoned. */
- char can_abandon;
};
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
@@ -1339,7 +1342,7 @@ struct sctp_endpoint {
* on every receive.
*/
__u8 *digest;
-
+
/* sendbuf acct. policy. */
__u32 sndbuf_policy;
@@ -1759,9 +1762,10 @@ struct sctp_association {
/* Default send parameters. */
__u16 default_stream;
__u16 default_flags;
+ __u16 default_pr_policy;
__u32 default_ppid;
__u32 default_context;
- __u32 default_timetolive;
+ __u32 default_pr_value;
/* Default receive parameters */
__u32 default_rcv_context;
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
index f205b10..74c0aba 100644
--- a/include/net/sctp/user.h
+++ b/include/net/sctp/user.h
@@ -71,7 +71,7 @@ enum sctp_optname {
#define SCTP_NODELAY SCTP_NODELAY
SCTP_AUTOCLOSE,
#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
- SCTP_SET_PEER_PRIMARY_ADDR,
+ SCTP_SET_PEER_PRIMARY_ADDR,
#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
SCTP_PRIMARY_ADDR,
#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
@@ -120,7 +120,7 @@ enum sctp_optname {
#define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
- /* Internal Socket Options. Some of the sctp library functions are
+ /* Internal Socket Options. Some of the sctp library functions are
* implemented using these socket options.
*/
SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
@@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
__u16 sinfo_stream;
__u16 sinfo_ssn;
__u16 sinfo_flags;
+ __u16 sinfo_pr_policy;
__u32 sinfo_ppid;
__u32 sinfo_context;
- __u32 sinfo_timetolive;
+ __u32 sinfo_pr_value;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
@@ -199,12 +200,25 @@ struct sctp_sndrcvinfo {
*/
enum sctp_sinfo_flags {
- SCTP_UNORDERED = 1, /* Send/receive message unordered. */
- SCTP_ADDR_OVER = 2, /* Override the primary destination. */
- SCTP_ABORT=4, /* Send an ABORT message to the peer. */
- SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. (0x0200) */
+ SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
+ SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
+ SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
};
+/*
+ * sinfo_pr_policy: 16 bits (unsigned integer)
+ *
+ * This field may contain the partial reliability used to
+ * send the message.
+ */
+
+enum sctp_sinfo_pr_policy {
+ SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
+ SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliability */
+ SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliability (EXPERIMENTAL) */
+ SCTP_PR_SCTP_RTX = 0x0003, /* Retransmis partial reliability (EXPERIMENTAL) */
+};
typedef union {
__u8 raw;
@@ -479,7 +493,7 @@ typedef enum sctp_sn_error {
*
* The protocol parameters used to initialize and bound retransmission
* timeout (RTO) are tunable. See [SCTP] for more information on how
- * these parameters are used in RTO calculation.
+ * these parameters are used in RTO calculation.
*/
struct sctp_rtoinfo {
sctp_assoc_t srto_assoc_id;
@@ -717,9 +731,9 @@ struct sctp_authchunks {
/*
* 8.3, 8.5 get all peer/local addresses in an association.
- * This parameter struct is used by SCTP_GET_PEER_ADDRS and
+ * This parameter struct is used by SCTP_GET_PEER_ADDRS and
* SCTP_GET_LOCAL_ADDRS socket options used internally to implement
- * sctp_getpaddrs() and sctp_getladdrs() API.
+ * sctp_getpaddrs() and sctp_getladdrs() API.
*/
struct sctp_getaddrs_old {
sctp_assoc_t assoc_id;
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: lksctp-dev-src-pr-20081216.diff --]
[-- Type: text/x-diff; name=lksctp-dev-src-pr-20081216.diff, Size: 7926 bytes --]
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index f4b2304..c178139 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->default_ppid = sp->default_ppid;
asoc->default_flags = sp->default_flags;
asoc->default_context = sp->default_context;
- asoc->default_timetolive = sp->default_timetolive;
+ asoc->default_pr_policy = sp->default_pr_policy;
+ asoc->default_pr_value = sp->default_pr_value;
asoc->default_rcv_context = sp->default_rcv_context;
/* AUTH related initializations */
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 1748ef9..4cdfe49 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
atomic_set(&msg->refcnt, 1);
msg->send_failed = 0;
msg->send_error = 0;
- msg->can_abandon = 0;
+ msg->expires_policy = SCTP_PR_SCTP_NONE;
msg->expires_at = 0;
INIT_LIST_HEAD(&msg->chunks);
}
@@ -170,13 +170,26 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
/* Note: Calculate this outside of the loop, so that all fragments
* have the same expiration.
*/
- if (sinfo->sinfo_timetolive) {
- /* sinfo_timetolive is in milliseconds */
- msg->expires_at = jiffies +
- msecs_to_jiffies(sinfo->sinfo_timetolive);
- msg->can_abandon = 1;
- SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
- __func__, msg, msg->expires_at, jiffies);
+
+ msg->expires_policy = sinfo->sinfo_pr_policy;
+
+ if(msg->expires_policy) {
+ switch(msg->expires_policy) {
+ case SCTP_PR_SCTP_TTL:
+ /* sinfo_timetolive is in milliseconds */
+ msg->expires_at = jiffies +
+ msecs_to_jiffies(sinfo->sinfo_pr_value);
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
+ __func__, msg, msg->expires_at, jiffies);
+ break;
+ case SCTP_PR_SCTP_BUF:
+ break;
+ case SCTP_PR_SCTP_RTX:
+ msg->expires_at = sinfo->sinfo_pr_value;
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_after: %ld retransmissions \n",
+ __func__, msg, msg->expires_at);
+ break;
+ }
}
max = asoc->frag_point;
@@ -291,11 +304,23 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
{
struct sctp_datamsg *msg = chunk->msg;
- if (!msg->can_abandon)
+ if (!msg->expires_policy)
return 0;
- if (time_after(jiffies, msg->expires_at))
- return 1;
+ switch(msg->expires_policy) {
+ case SCTP_PR_SCTP_TTL:
+ if (time_after(jiffies, msg->expires_at))
+ return 1;
+ case SCTP_PR_SCTP_BUF:
+ /* TODO: Implement this */
+ return 0;
+ case SCTP_PR_SCTP_RTX:
+ if(--msg->expires_at <= 0) {
+ SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld EXPIRED!!\n",
+ __func__, msg, msg->expires_at);
+ return 1;
+ }
+ }
return 0;
}
diff --git a/net/sctp/output.c b/net/sctp/output.c
index c3f417f..b344a9d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
asoc->peer.rwnd = rwnd;
/* Has been accepted for transmission. */
if (!asoc->peer.prsctp_capable)
- chunk->msg->can_abandon = 0;
+ chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
finish:
return retval;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1b9045..0dfc137 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
default_sinfo.sinfo_flags = asoc->default_flags;
default_sinfo.sinfo_ppid = asoc->default_ppid;
default_sinfo.sinfo_context = asoc->default_context;
- default_sinfo.sinfo_timetolive = asoc->default_timetolive;
+ default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
+ default_sinfo.sinfo_pr_value = asoc->default_pr_value;
default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
sinfo = &default_sinfo;
}
@@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
+ * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*/
static int sctp_setsockopt_default_send_param(struct sock *sk,
@@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
asoc->default_flags = info.sinfo_flags;
asoc->default_ppid = info.sinfo_ppid;
asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_pr_policy = info.sinfo_pr_policy;
+ asoc->default_pr_value = info.sinfo_pr_value;
} else {
sp->default_stream = info.sinfo_stream;
sp->default_flags = info.sinfo_flags;
sp->default_ppid = info.sinfo_ppid;
sp->default_context = info.sinfo_context;
- sp->default_timetolive = info.sinfo_timetolive;
+ sp->default_pr_policy = info.sinfo_pr_policy;
+ sp->default_pr_value = info.sinfo_pr_value;
}
return 0;
@@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->default_ppid = 0;
sp->default_flags = 0;
sp->default_context = 0;
- sp->default_timetolive = 0;
+ sp->default_pr_policy = 0;
+ sp->default_pr_value = 0;
sp->default_rcv_context = 0;
sp->max_burst = sctp_max_burst;
@@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
* in to this call the sctp_sndrcvinfo structure defined in Section
* 5.2.2) The input parameters accepted by this call include
* sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
- * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
+ * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
* to this call if the caller is using the UDP model.
*
* For getsockopt, it get the default sctp_sndrcvinfo structure.
@@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
info.sinfo_flags = asoc->default_flags;
info.sinfo_ppid = asoc->default_ppid;
info.sinfo_context = asoc->default_context;
- info.sinfo_timetolive = asoc->default_timetolive;
+ info.sinfo_pr_policy = asoc->default_pr_policy;
+ info.sinfo_pr_value = asoc->default_pr_value;
} else {
info.sinfo_stream = sp->default_stream;
info.sinfo_flags = sp->default_flags;
info.sinfo_ppid = sp->default_ppid;
info.sinfo_context = sp->default_context;
- info.sinfo_timetolive = sp->default_timetolive;
+ info.sinfo_pr_policy = sp->default_pr_policy;
+ info.sinfo_pr_value = sp->default_pr_value;
}
if (put_user(len, optlen))
@@ -6107,10 +6113,17 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
(struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
/* Minimally, validate the sinfo_flags. */
+
+ /* TODO this validation does not work with the new
+ * SCTP_PR_SCTP_XXX flags
+ */
+
+ /*
if (cmsgs->info->sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
+ */
break;
default:
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 5f186ca..2c6f111 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
sinfo.sinfo_context = event->asoc->default_rcv_context;
/* These fields are not used while receiving. */
- sinfo.sinfo_timetolive = 0;
+ sinfo.sinfo_pr_policy = 0;
+ sinfo.sinfo_pr_value = 0;
put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: lksctp-tools-pr-20081216.diff --]
[-- Type: text/x-diff; name=lksctp-tools-pr-20081216.diff, Size: 25403 bytes --]
diff --git a/src/func_tests/Makefile.am b/src/func_tests/Makefile.am
index b985685..a7167d5 100644
--- a/src/func_tests/Makefile.am
+++ b/src/func_tests/Makefile.am
@@ -5,7 +5,7 @@ include $(top_srcdir)/Makefile.rules
include $(top_srcdir)/Makefile.dirs
# General compilation flags
-INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
+INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
AM_CFLAGS = -g -Wall -Wstrict-prototypes -Wimplicit-function-declaration
AM_LDFLAGS = -lpthread
LDADD = $(top_builddir)/src/lib/libsctp.la \
@@ -27,6 +27,7 @@ PASSING_KERN_TESTS = \
test_connectx \
test_recvmsg \
test_timetolive \
+ test_rtxtolive \
test_sctp_sendrecvmsg \
test_getname \
test_tcp_style\
@@ -55,6 +56,7 @@ PASSING_V6_KERN_TESTS = \
test_inaddr_any_v6 \
test_peeloff_v6 \
test_timetolive_v6 \
+ test_rtxtolive_v6 \
test_sctp_sendrecvmsg_v6 \
test_getname_v6 \
test_tcp_style_v6
@@ -102,21 +104,22 @@ v6test: ${PASSING_V6_KERN_TESTS}
@echo "Hoody hoo!"
# Specifying the sources
-test_assoc_abort_SOURCES = test_assoc_abort.c
-test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
-test_autoclose_SOURCES = test_autoclose.c
-test_basic_SOURCES = test_basic.c
-test_fragments_SOURCES = test_fragments.c
-test_inaddr_any_SOURCES = test_inaddr_any.c
-test_peeloff_SOURCES = test_peeloff.c
-test_sockopt_SOURCES = test_sockopt.c
-test_connect_SOURCES = test_connect.c
-test_connectx_SOURCES = test_connectx.c
-test_recvmsg_SOURCES = test_recvmsg.c
+test_assoc_abort_SOURCES = test_assoc_abort.c
+test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
+test_autoclose_SOURCES = test_autoclose.c
+test_basic_SOURCES = test_basic.c
+test_fragments_SOURCES = test_fragments.c
+test_inaddr_any_SOURCES = test_inaddr_any.c
+test_peeloff_SOURCES = test_peeloff.c
+test_sockopt_SOURCES = test_sockopt.c
+test_connect_SOURCES = test_connect.c
+test_connectx_SOURCES = test_connectx.c
+test_recvmsg_SOURCES = test_recvmsg.c
test_timetolive_SOURCES = test_timetolive.c
+test_rtxtolive_SOURCES = test_rtxtolive.c
test_sctp_sendrecvmsg_SOURCES = test_sctp_sendrecvmsg.c
-test_getname_SOURCES = test_getname.c
-test_tcp_style_SOURCES = test_tcp_style.c
+test_getname_SOURCES = test_getname.c
+test_tcp_style_SOURCES = test_tcp_style.c
test_1_to_1_socket_bind_listen_SOURCES = test_1_to_1_socket_bind_listen.c
test_1_to_1_accept_close_SOURCES = test_1_to_1_accept_close.c
@@ -157,6 +160,9 @@ test_peeloff_v6_CFLAGS = ${V6FLAGS}
test_timetolive_v6_SOURCES = test_timetolive.c
test_timetolive_v6_CFLAGS = ${V6FLAGS}
+test_rtxtolive_v6_SOURCES = test_rtxtolive.c
+test_rtxtolive_v6_CFLAGS = ${V6FLAGS}
+
test_sctp_sendrecvmsg_v6_SOURCES = test_sctp_sendrecvmsg.c
test_sctp_sendrecvmsg_v6_CFLAGS = ${V6FLAGS}
diff --git a/src/func_tests/test_rtxtolive.c b/src/func_tests/test_rtxtolive.c
new file mode 100644
index 0000000..9aa03ad
--- /dev/null
+++ b/src/func_tests/test_rtxtolive.c
@@ -0,0 +1,410 @@
+/* SCTP kernel Implementation
+ * (C) Copyright IBM Corp. 2001, 2003
+ * Copyright (c) 1999-2000 Cisco, Inc.
+ * Copyright (c) 1999-2001 Motorola, Inc.
+ * Copyright (c) 2001 Intel Corp.
+ * Copyright (c) 2001 Nokia, Inc.
+ *
+ * The SCTP implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ * lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ * http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ * Jon Grimm <jgrimm@us.ibm.com>
+ * Sridhar Samudrala <sri@us.ibm.com>
+ */
+
+/*
+ * This is a basic functional test for the SCTP kernel
+ * implementation of sndrcvinfo.sinfo_pr_value.
+ *
+ * 1) Create two sockets, the listening socket sets its RECVBUF small
+ * 2) Create a connection. Send enough data to the non-reading listener
+ * to fill the RCVBUF.
+ * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
+ * 6) Disable sinfo_pr_value on a message and send.
+ * 7) Wait sinfo_pr_value time.
+ * 8) Read out all the data at the receiver.
+ * 9) Make sure timed out message did not make it.
+ * 10) Make sure that the message with no timeout makes it to the receiver.
+ *
+ * Also test with SEND_FAILED notifications. Also, use a fragmented
+ * message so as to also exercise the SEND_FAILED of fragmentation
+ * code.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <netinet/in.h>
+#include <sys/errno.h>
+#include <errno.h>
+#include <netinet/sctp.h>
+#include <sctputil.h>
+
+char *TCID = __FILE__;
+int TST_TOTAL = 6;
+int TST_CNT = 0;
+
+/* This is the size of our RCVBUF */
+#define SMALL_RCVBUF 3000
+
+/* MAX segment size */
+#define SMALL_MAXSEG 100
+
+/* RWND_SLOP is the extra data that fills up the rwnd */
+#define RWND_SLOP 100
+static char *fillmsg = NULL;
+static char *ttlmsg = "This should time out!\n";
+static char *nottlmsg = "This should NOT time out!\n";
+static char ttlfrag[SMALL_MAXSEG*3] = {0};
+static char *message = "Hello world\n";
+
+int main(int argc, char *argv[])
+{
+ int sk1, sk2;
+ sockaddr_storage_t loop1;
+ sockaddr_storage_t loop2;
+ struct iovec iov;
+ struct msghdr inmessage;
+ struct msghdr outmessage;
+ char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct iovec out_iov;
+ int error;
+ int pf_class, af_family;
+ uint32_t ppid;
+ uint32_t stream;
+ sctp_assoc_t associd1, associd2;
+ struct sctp_assoc_change *sac;
+ struct sctp_event_subscribe subscribe;
+ char *big_buffer;
+ int offset;
+ struct sctp_send_failed *ssf;
+ int len; /* Really becomes 2xlen when set. */
+ int orig_len;
+ struct sctp_status gstatus;
+
+ /* Rather than fflush() throughout the code, set stdout to
+ * be unbuffered.
+ */
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ /* Set some basic values which depend on the address family. */
+#if TEST_V6
+ pf_class = PF_INET6;
+ af_family = AF_INET6;
+
+ loop1.v6.sin6_family = AF_INET6;
+ loop1.v6.sin6_addr = in6addr_loopback;
+ loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v6.sin6_family = AF_INET6;
+ loop2.v6.sin6_addr = in6addr_loopback;
+ loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
+#else
+ pf_class = PF_INET;
+ af_family = AF_INET;
+
+ loop1.v4.sin_family = AF_INET;
+ loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
+
+ loop2.v4.sin_family = AF_INET;
+ loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
+ loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
+#endif /* TEST_V6 */
+
+ /* Create the two endpoints which will talk to each other. */
+ sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+ sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
+
+ len = sizeof(int);
+ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
+ &len);
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
+ strerror(errno));
+ /* Set the MAXSEG to something smallish. */
+ {
+ int val = SMALL_MAXSEG;
+ test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
+ }
+
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ subscribe.sctp_send_failure_event = 1;
+ test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+ test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
+
+ /* Bind these sockets to the test ports. */
+ test_bind(sk1, &loop1.sa, sizeof(loop1));
+ test_bind(sk2, &loop2.sa, sizeof(loop2));
+
+ /*
+ * This code sets the associations RWND very small so we can
+ * fill it. It does this by manipulating the rcvbuf as follows:
+ * 1) Reduce the rcvbuf size on the socket
+ * 2) create an association so that we advertize rcvbuf/2 as
+ * our initial rwnd
+ * 3) raise the rcvbuf value so that we don't drop data wile
+ * receiving later data
+ */
+ len = SMALL_RCVBUF;
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len,
+ sizeof(len));
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Mark sk2 as being able to accept new associations. */
+ test_listen(sk2, 1);
+
+ /* Send the first message. This will create the association. */
+ outmessage.msg_name = &loop2;
+ outmessage.msg_namelen = sizeof(loop2);
+ outmessage.msg_iov = &out_iov;
+ outmessage.msg_iovlen = 1;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid = rand(); /* Choose an arbitrary value. */
+ stream = 1;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = message;
+ outmessage.msg_iov->iov_len = strlen(message) + 1;
+ test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
+
+ /* Initialize inmessage for all receives. */
+ big_buffer = test_malloc(REALLY_BIG);
+ memset(&inmessage, 0, sizeof(inmessage));
+ iov.iov_base = big_buffer;
+ iov.iov_len = REALLY_BIG;
+ inmessage.msg_iov = &iov;
+ inmessage.msg_iovlen = 1;
+ inmessage.msg_control = incmsg;
+
+ /* Get the communication up message on sk2. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd2 = sac->sac_assoc_id;
+
+ /* Get the communication up message on sk1. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
+ sac = (struct sctp_assoc_change *)iov.iov_base;
+ associd1 = sac->sac_assoc_id;
+
+ /* restore the rcvbuffer size for the receiving socket */
+ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
+ sizeof(orig_len));
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
+ strerror(errno));
+
+ /* Get the first data message which was sent. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(message) + 1,
+ MSG_EOR, stream, ppid);
+
+ /* Figure out how big to make our fillmsg */
+ len = sizeof(struct sctp_status);
+ memset(&gstatus,0,sizeof(struct sctp_status));
+ gstatus.sstat_assoc_id = associd1;
+ error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
+
+ if (error)
+ tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
+ strerror(errno));
+ tst_resm(TINFO, "Creating fillmsg of size %d",
+ gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
+
+ /* Send a fillmsg */
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = 0;
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ ppid++;
+ stream++;
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
+ fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
+ outmessage.msg_iov->iov_base = fillmsg;
+ outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
+ gstatus.sstat_rwnd+RWND_SLOP);
+
+ /* Now send the message with timeout. */
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = ttlmsg;
+ outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
+ sinfo->sinfo_pr_value = 2;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
+
+ tst_resm(TPASS, "Send a message with timeout");
+
+ /* Next send a message with no timeout. */
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ outmessage.msg_iov->iov_base = nottlmsg;
+ outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1;
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
+
+ tst_resm(TPASS, "Send a message with no timeout");
+
+ /* And finally a fragmented message that will time out. */
+ sinfo->sinfo_ppid = ppid;
+ sinfo->sinfo_stream = stream;
+ memset(ttlfrag, '0', sizeof(ttlfrag));
+ ttlfrag[sizeof(ttlfrag)-1] = '\0';
+ outmessage.msg_iov->iov_base = ttlfrag;
+ outmessage.msg_iov->iov_len = sizeof(ttlfrag);
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ sinfo->sinfo_assoc_id = associd1;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
+ sinfo->sinfo_pr_value = 2;
+ test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
+
+ tst_resm(TPASS, "Send a fragmented message with timeout");
+
+ /* Sleep waiting for the message to time out. */
+ tst_resm(TINFO, " ** SLEEPING for 3 seconds **");
+ sleep(3);
+
+ /* Read the fillmsg snuck in between the ttl'd messages. */
+ do {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ } while (!(inmessage.msg_flags & MSG_EOR));
+
+ /* Now get the message that did NOT time out. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1,
+ MSG_EOR, stream, ppid);
+ if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1))
+ tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!");
+
+ tst_resm(TPASS, "Receive message with no timeout");
+
+ /* Get the SEND_FAILED notification for the message that DID
+ * time out.
+ */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_send_failed) +
+ strlen(ttlmsg) + 1,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)iov.iov_base;
+ if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+
+ tst_resm(TPASS, "Receive SEND_FAILED for message with timeout");
+
+ /* Get the SEND_FAILED notification for the fragmented message that
+ * DID time out.
+ */
+ offset = 0;
+ do {
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_send_failed) +
+ SMALL_MAXSEG,
+ SCTP_SEND_FAILED, 0);
+ ssf = (struct sctp_send_failed *)iov.iov_base;
+ if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
+ SMALL_MAXSEG))
+ tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
+ offset += SMALL_MAXSEG;
+ } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */
+
+ tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with "
+ "timeout");
+
+ /* Shut down the link. */
+ close(sk1);
+
+ /* Get the shutdown complete notification. */
+ inmessage.msg_controllen = sizeof(incmsg);
+ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
+ test_check_msg_notification(&inmessage, error,
+ sizeof(struct sctp_assoc_change),
+ SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
+
+ close(sk2);
+
+ /* Indicate successful completion. */
+ return 0;
+}
diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
index c275e45..aaa56e9 100644
--- a/src/func_tests/test_sctp_sendrecvmsg.c
+++ b/src/func_tests/test_sctp_sendrecvmsg.c
@@ -243,7 +243,7 @@ int main(int argc, char *argv[])
/* Now send a message that will timeout. */
test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
(struct sockaddr *)&loop2, sizeof(loop2),
- ppid, 0, stream, 2000, 0);
+ ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
tst_resm(TPASS, "sctp_sendmsg with ttl");
@@ -259,7 +259,7 @@ int main(int argc, char *argv[])
ttlfrag[sizeof(ttlfrag)-1] = '\0';
test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
(struct sockaddr *)&loop2, sizeof(loop2),
- ppid, 0, stream, 2000, 0);
+ ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
@@ -335,7 +335,8 @@ int main(int argc, char *argv[])
snd_sinfo.sinfo_ppid = rand();
snd_sinfo.sinfo_flags = 0;
snd_sinfo.sinfo_stream = 2;
- snd_sinfo.sinfo_timetolive = 0;
+ snd_sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ snd_sinfo.sinfo_pr_value = 0;
snd_sinfo.sinfo_assoc_id = associd1;
test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
MSG_NOSIGNAL);
diff --git a/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
index d9bdf1b..dc66722 100644
--- a/src/func_tests/test_timetolive.c
+++ b/src/func_tests/test_timetolive.c
@@ -39,14 +39,14 @@
/*
* This is a basic functional test for the SCTP kernel
- * implementation of sndrcvinfo.sinfo_timetolive.
+ * implementation of sndrcvinfo.sinfo_pr_value.
*
* 1) Create two sockets, the listening socket sets its RECVBUF small
* 2) Create a connection. Send enough data to the non-reading listener
* to fill the RCVBUF.
- * 5) Set sinfo_timetolive on a message and send.
- * 6) Disable sinfo_timetolive on a message and send.
- * 7) Wait sinfo_timetolive.
+ * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
+ * 6) Disable sinfo_pr_value on a message and send.
+ * 7) Wait sinfo_pr_value time.
* 8) Read out all the data at the receiver.
* 9) Make sure timed out message did not make it.
* 10) Make sure that the message with no timeout makes it to the receiver.
@@ -288,7 +288,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 0;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
gstatus.sstat_rwnd+RWND_SLOP);
@@ -300,7 +301,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 2000;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ sinfo->sinfo_pr_value = 2000;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
tst_resm(TPASS, "Send a message with timeout");
@@ -313,7 +315,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 0;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+ sinfo->sinfo_pr_value = 0;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
tst_resm(TPASS, "Send a message with no timeout");
@@ -328,7 +331,8 @@ int main(int argc, char *argv[])
outmessage.msg_name = NULL;
outmessage.msg_namelen = 0;
sinfo->sinfo_assoc_id = associd1;
- sinfo->sinfo_timetolive = 2000;
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
+ sinfo->sinfo_pr_value = 2000;
test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
tst_resm(TPASS, "Send a fragmented message with timeout");
diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h
index ae557a5..5a6cea2 100644
--- a/src/include/netinet/sctp.h
+++ b/src/include/netinet/sctp.h
@@ -184,9 +184,10 @@ struct sctp_sndrcvinfo {
__u16 sinfo_stream;
__u16 sinfo_ssn;
__u16 sinfo_flags;
+ __u16 sinfo_pr_policy;
__u32 sinfo_ppid;
__u32 sinfo_context;
- __u32 sinfo_timetolive;
+ __u32 sinfo_pr_value;
__u32 sinfo_tsn;
__u32 sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
@@ -200,12 +201,25 @@ struct sctp_sndrcvinfo {
*/
enum sctp_sinfo_flags {
- SCTP_UNORDERED = 1, /* Send/receive message unordered. */
- SCTP_ADDR_OVER = 2, /* Override the primary destination. */
- SCTP_ABORT=4, /* Send an ABORT message to the peer. */
- SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
+ SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
+ SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
+ SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
};
+/*
+ * sinfo_pr_policy: 16 bits (unsigned integer)
+ *
+ * This field may contain the partial reliability used to
+ * send the message.
+ */
+
+enum sctp_sinfo_pr_policy {
+ SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
+ SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliable */
+ SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliable */
+ SCTP_PR_SCTP_RTX = 0x0003, /* Retransmist partial reliable */
+};
typedef union {
__u8 raw;
@@ -816,7 +830,7 @@ int sctp_freeladdrs(struct sockaddr *addrs);
*/
int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
socklen_t tolen, uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive, uint32_t context);
+ uint16_t stream_no, uint32_t pr_value, uint32_t context);
/* This library function assist the user with sending a message without
* dealing directly with the CMSG header.
diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
index 1de592d..a674646 100644
--- a/src/lib/sendmsg.c
+++ b/src/lib/sendmsg.c
@@ -31,7 +31,7 @@
int
sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
socklen_t tolen, uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive, uint32_t context)
+ uint16_t stream_no, uint32_t pr_value, uint32_t context)
{
struct msghdr outmsg;
struct iovec iov;
@@ -61,9 +61,22 @@ sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
sinfo->sinfo_ppid = ppid;
sinfo->sinfo_flags = flags;
sinfo->sinfo_stream = stream_no;
- sinfo->sinfo_timetolive = timetolive;
sinfo->sinfo_context = context;
+ sinfo->sinfo_pr_policy = sinfo->sinfo_flags & 0xff;
+ sinfo->sinfo_pr_value = pr_value;
+
+ printf("sinfo_flags: %x sinfo_pr_policy: %d sinfo_pr_value: %d\n",
+ sinfo->sinfo_flags, sinfo->sinfo_pr_policy, sinfo->sinfo_pr_value);
+
+ /* If we get an invalid sinfo_pr_policy force it to
+ * SCTP_PR_SCTP_NONE or shall we better fail and set a
+ * EINVAL error??
+ */
+
+ if(sinfo->sinfo_pr_policy > SCTP_PR_SCTP_RTX)
+ sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
+
return sendmsg(s, &outmsg, 0);
}
diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
index 347c91b..0afbc36 100644
--- a/src/testlib/sctputil.h
+++ b/src/testlib/sctputil.h
@@ -270,11 +270,11 @@ static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
struct sockaddr *to, socklen_t tolen,
uint32_t ppid, uint32_t flags,
- uint16_t stream_no, uint32_t timetolive,
+ uint16_t stream_no, uint32_t pr_value,
uint32_t context)
{
int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
- timetolive, context);
+ pr_value, context);
if (len != error)
tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
error, errno);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] Replace timetolive with pr_policy and pr_value
2008-12-03 1:59 [PATCH] Replace timetolive with pr_policy and pr_value Horacio Sanson
2008-12-03 7:15 ` Horacio Sanson
2008-12-15 9:56 ` Horacio Sanson
@ 2008-12-15 15:55 ` Vlad Yasevich
2008-12-16 7:53 ` Horacio Sanson
2008-12-16 14:33 ` Vlad Yasevich
4 siblings, 0 replies; 6+ messages in thread
From: Vlad Yasevich @ 2008-12-15 15:55 UTC (permalink / raw)
To: linux-sctp
> I created a new patch set that fixes the SCTP_PR_SCTP_RTX partial
> reliability that was not working and added a test program to test it.
> Again all v4tests and v6tests pass including my own tests.
>
> This includes the previous patches so the previous ones should be
> ignored. But no one seems to be looking at my patches so I think there
> should be no problems anyway :( .
>
>
I am looking, I am just busy with other things as well. Please be patient.
As a first step that will make review much easier, please get rid of the whitespace
changes that show up. That will improve the readability of the patches.
Also, please separate the patches into separate e-mails. Look at git-send-email
and git-format-patch for more information.
Thanks
-vlad
>
>
>
> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
> index 9661d7b..ffda4c5 100644
> --- a/include/net/sctp/structs.h
> +++ b/include/net/sctp/structs.h
> @@ -208,7 +208,7 @@ extern struct sctp_globals {
>
> /* Lock that protects the local_addr_list writers */
> spinlock_t addr_list_lock;
> -
> +
> /* Flag to indicate if addip is enabled. */
> int addip_enable;
> int addip_noauth_enable;
> @@ -282,7 +282,8 @@ struct sctp_sock {
> __u32 default_ppid;
> __u16 default_flags;
> __u32 default_context;
> - __u32 default_timetolive;
> + __u16 default_pr_policy;
> + __u32 default_pr_value;
Please don't add any memory holes when adding new entries to the structure.
> __u32 default_rcv_context;
> int max_burst;
>
> @@ -390,7 +391,7 @@ struct sctp_cookie {
> /* This holds the originating address of the INIT packet. */
> union sctp_addr peer_addr;
>
> - /* IG Section 2.35.3
> + /* IG Section 2.35.3
> * Include the source port of the INIT-ACK
> */
> __u16 my_port;
> @@ -398,7 +399,7 @@ struct sctp_cookie {
> __u8 prsctp_capable;
>
> /* Padding for future use */
> - __u8 padding;
> + __u8 padding;
White space? Please limit the scope of your patches.
>
> __u32 adaptation_ind;
>
> @@ -512,12 +513,12 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
> }
>
> /* Skip over this ssn and all below. */
> -static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
> +static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
> __u16 ssn)
> {
> stream->ssn[id] = ssn+1;
> }
> -
> +
More whitespace?
> /*
> * Pointers to address related SCTP functions.
> * (i.e. things that depend on the address family.)
> @@ -575,7 +576,7 @@ struct sctp_af {
> union sctp_addr_param *,
> __be16 port, int iif);
> int (*to_addr_param) (const union sctp_addr *,
> - union sctp_addr_param *);
> + union sctp_addr_param *);
Again?
> int (*addr_valid) (union sctp_addr *,
> struct sctp_sock *,
> const struct sk_buff *);
> @@ -626,13 +627,15 @@ struct sctp_datamsg {
> struct list_head track;
> /* Reference counting. */
> atomic_t refcnt;
> +
> + /* Policy used to determine expired messages */
> + unsigned long expires_policy;
> /* When is this message no longer interesting to the peer? */
> unsigned long expires_at;
> /* Did the messenge fail to send? */
> int send_error;
> char send_failed;
> /* Control whether chunks from this message can be abandoned. */
> - char can_abandon;
> };
>
> struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
> @@ -1339,7 +1342,7 @@ struct sctp_endpoint {
> * on every receive.
> */
> __u8 *digest;
> -
> +
Again? I am done at this point!!!
> /* sendbuf acct. policy. */
> __u32 sndbuf_policy;
>
> @@ -1759,9 +1762,10 @@ struct sctp_association {
> /* Default send parameters. */
> __u16 default_stream;
> __u16 default_flags;
> + __u16 default_pr_policy;
> __u32 default_ppid;
> __u32 default_context;
> - __u32 default_timetolive;
> + __u32 default_pr_value;
>
> /* Default receive parameters */
> __u32 default_rcv_context;
> diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
> index f205b10..74c0aba 100644
> --- a/include/net/sctp/user.h
> +++ b/include/net/sctp/user.h
> @@ -71,7 +71,7 @@ enum sctp_optname {
> #define SCTP_NODELAY SCTP_NODELAY
> SCTP_AUTOCLOSE,
> #define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
> - SCTP_SET_PEER_PRIMARY_ADDR,
> + SCTP_SET_PEER_PRIMARY_ADDR,
> #define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
> SCTP_PRIMARY_ADDR,
> #define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
> @@ -120,7 +120,7 @@ enum sctp_optname {
> #define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
>
>
> - /* Internal Socket Options. Some of the sctp library functions are
> + /* Internal Socket Options. Some of the sctp library functions are
> * implemented using these socket options.
> */
> SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
> @@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
> __u16 sinfo_stream;
> __u16 sinfo_ssn;
> __u16 sinfo_flags;
> + __u16 sinfo_pr_policy;
> __u32 sinfo_ppid;
> __u32 sinfo_context;
> - __u32 sinfo_timetolive;
> + __u32 sinfo_pr_value;
> __u32 sinfo_tsn;
> __u32 sinfo_cumtsn;
> sctp_assoc_t sinfo_assoc_id;
> @@ -199,12 +200,25 @@ struct sctp_sndrcvinfo {
> */
>
> enum sctp_sinfo_flags {
> - SCTP_UNORDERED = 1, /* Send/receive message unordered. */
> - SCTP_ADDR_OVER = 2, /* Override the primary destination. */
> - SCTP_ABORT=4, /* Send an ABORT message to the peer. */
> - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
> + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. (0x0200) */
> + SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
> + SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
> + SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
> };
>
> +/*
> + * sinfo_pr_policy: 16 bits (unsigned integer)
> + *
> + * This field may contain the partial reliability used to
> + * send the message.
> + */
> +
> +enum sctp_sinfo_pr_policy {
> + SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
> + SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliability */
> + SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliability (EXPERIMENTAL) */
> + SCTP_PR_SCTP_RTX = 0x0003, /* Retransmis partial reliability (EXPERIMENTAL) */
> +};
>
> typedef union {
> __u8 raw;
> @@ -479,7 +493,7 @@ typedef enum sctp_sn_error {
> *
> * The protocol parameters used to initialize and bound retransmission
> * timeout (RTO) are tunable. See [SCTP] for more information on how
> - * these parameters are used in RTO calculation.
> + * these parameters are used in RTO calculation.
> */
> struct sctp_rtoinfo {
> sctp_assoc_t srto_assoc_id;
> @@ -717,9 +731,9 @@ struct sctp_authchunks {
>
> /*
> * 8.3, 8.5 get all peer/local addresses in an association.
> - * This parameter struct is used by SCTP_GET_PEER_ADDRS and
> + * This parameter struct is used by SCTP_GET_PEER_ADDRS and
> * SCTP_GET_LOCAL_ADDRS socket options used internally to implement
> - * sctp_getpaddrs() and sctp_getladdrs() API.
> + * sctp_getpaddrs() and sctp_getladdrs() API.
> */
> struct sctp_getaddrs_old {
> sctp_assoc_t assoc_id;
>
>
>
> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> index f4b2304..c178139 100644
> --- a/net/sctp/associola.c
> +++ b/net/sctp/associola.c
> @@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
> asoc->default_ppid = sp->default_ppid;
> asoc->default_flags = sp->default_flags;
> asoc->default_context = sp->default_context;
> - asoc->default_timetolive = sp->default_timetolive;
> + asoc->default_pr_policy = sp->default_pr_policy;
> + asoc->default_pr_value = sp->default_pr_value;
> asoc->default_rcv_context = sp->default_rcv_context;
>
> /* AUTH related initializations */
> diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
> index 1748ef9..4cdfe49 100644
> --- a/net/sctp/chunk.c
> +++ b/net/sctp/chunk.c
> @@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
> atomic_set(&msg->refcnt, 1);
> msg->send_failed = 0;
> msg->send_error = 0;
> - msg->can_abandon = 0;
> + msg->expires_policy = SCTP_PR_SCTP_NONE;
> msg->expires_at = 0;
> INIT_LIST_HEAD(&msg->chunks);
> }
> @@ -170,13 +170,26 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
> /* Note: Calculate this outside of the loop, so that all fragments
> * have the same expiration.
> */
> - if (sinfo->sinfo_timetolive) {
> - /* sinfo_timetolive is in milliseconds */
> - msg->expires_at = jiffies +
> - msecs_to_jiffies(sinfo->sinfo_timetolive);
> - msg->can_abandon = 1;
> - SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
> - __func__, msg, msg->expires_at, jiffies);
> +
> + msg->expires_policy = sinfo->sinfo_pr_policy;
> +
> + if(msg->expires_policy) {
> + switch(msg->expires_policy) {
> + case SCTP_PR_SCTP_TTL:
> + /* sinfo_timetolive is in milliseconds */
> + msg->expires_at = jiffies +
> + msecs_to_jiffies(sinfo->sinfo_pr_value);
> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
> + __func__, msg, msg->expires_at, jiffies);
> + break;
> + case SCTP_PR_SCTP_BUF:
> + break;
> + case SCTP_PR_SCTP_RTX:
> + msg->expires_at = sinfo->sinfo_pr_value;
> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_after: %ld retransmissions \n",
> + __func__, msg, msg->expires_at);
> + break;
> + }
> }
>
> max = asoc->frag_point;
> @@ -291,11 +304,23 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
> {
> struct sctp_datamsg *msg = chunk->msg;
>
> - if (!msg->can_abandon)
> + if (!msg->expires_policy)
> return 0;
>
> - if (time_after(jiffies, msg->expires_at))
> - return 1;
> + switch(msg->expires_policy) {
> + case SCTP_PR_SCTP_TTL:
> + if (time_after(jiffies, msg->expires_at))
> + return 1;
> + case SCTP_PR_SCTP_BUF:
> + /* TODO: Implement this */
> + return 0;
> + case SCTP_PR_SCTP_RTX:
> + if(--msg->expires_at <= 0) {
> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld EXPIRED!!\n",
> + __func__, msg, msg->expires_at);
> + return 1;
> + }
> + }
>
> return 0;
> }
> diff --git a/net/sctp/output.c b/net/sctp/output.c
> index c3f417f..b344a9d 100644
> --- a/net/sctp/output.c
> +++ b/net/sctp/output.c
> @@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
> asoc->peer.rwnd = rwnd;
> /* Has been accepted for transmission. */
> if (!asoc->peer.prsctp_capable)
> - chunk->msg->can_abandon = 0;
> + chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
>
> finish:
> return retval;
> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
> index a1b9045..0dfc137 100644
> --- a/net/sctp/socket.c
> +++ b/net/sctp/socket.c
> @@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
> default_sinfo.sinfo_flags = asoc->default_flags;
> default_sinfo.sinfo_ppid = asoc->default_ppid;
> default_sinfo.sinfo_context = asoc->default_context;
> - default_sinfo.sinfo_timetolive = asoc->default_timetolive;
> + default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
> + default_sinfo.sinfo_pr_value = asoc->default_pr_value;
> default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
> sinfo = &default_sinfo;
> }
> @@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
> * in to this call the sctp_sndrcvinfo structure defined in Section
> * 5.2.2) The input parameters accepted by this call include
> * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
> - * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
> + * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
> * to this call if the caller is using the UDP model.
> */
> static int sctp_setsockopt_default_send_param(struct sock *sk,
> @@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
> asoc->default_flags = info.sinfo_flags;
> asoc->default_ppid = info.sinfo_ppid;
> asoc->default_context = info.sinfo_context;
> - asoc->default_timetolive = info.sinfo_timetolive;
> + asoc->default_pr_policy = info.sinfo_pr_policy;
> + asoc->default_pr_value = info.sinfo_pr_value;
> } else {
> sp->default_stream = info.sinfo_stream;
> sp->default_flags = info.sinfo_flags;
> sp->default_ppid = info.sinfo_ppid;
> sp->default_context = info.sinfo_context;
> - sp->default_timetolive = info.sinfo_timetolive;
> + sp->default_pr_policy = info.sinfo_pr_policy;
> + sp->default_pr_value = info.sinfo_pr_value;
> }
>
> return 0;
> @@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
> sp->default_ppid = 0;
> sp->default_flags = 0;
> sp->default_context = 0;
> - sp->default_timetolive = 0;
> + sp->default_pr_policy = 0;
> + sp->default_pr_value = 0;
>
> sp->default_rcv_context = 0;
> sp->max_burst = sctp_max_burst;
> @@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
> * in to this call the sctp_sndrcvinfo structure defined in Section
> * 5.2.2) The input parameters accepted by this call include
> * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
> - * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
> + * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
> * to this call if the caller is using the UDP model.
> *
> * For getsockopt, it get the default sctp_sndrcvinfo structure.
> @@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
> info.sinfo_flags = asoc->default_flags;
> info.sinfo_ppid = asoc->default_ppid;
> info.sinfo_context = asoc->default_context;
> - info.sinfo_timetolive = asoc->default_timetolive;
> + info.sinfo_pr_policy = asoc->default_pr_policy;
> + info.sinfo_pr_value = asoc->default_pr_value;
> } else {
> info.sinfo_stream = sp->default_stream;
> info.sinfo_flags = sp->default_flags;
> info.sinfo_ppid = sp->default_ppid;
> info.sinfo_context = sp->default_context;
> - info.sinfo_timetolive = sp->default_timetolive;
> + info.sinfo_pr_policy = sp->default_pr_policy;
> + info.sinfo_pr_value = sp->default_pr_value;
> }
>
> if (put_user(len, optlen))
> @@ -6107,10 +6113,17 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
> (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>
> /* Minimally, validate the sinfo_flags. */
> +
> + /* TODO this validation does not work with the new
> + * SCTP_PR_SCTP_XXX flags
> + */
> +
> + /*
> if (cmsgs->info->sinfo_flags &
> ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
> SCTP_ABORT | SCTP_EOF))
> return -EINVAL;
> + */
> break;
>
> default:
> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
> index 5f186ca..2c6f111 100644
> --- a/net/sctp/ulpevent.c
> +++ b/net/sctp/ulpevent.c
> @@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
> sinfo.sinfo_context = event->asoc->default_rcv_context;
>
> /* These fields are not used while receiving. */
> - sinfo.sinfo_timetolive = 0;
> + sinfo.sinfo_pr_policy = 0;
> + sinfo.sinfo_pr_value = 0;
>
> put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
> sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
>
>
>
> diff --git a/src/func_tests/Makefile.am b/src/func_tests/Makefile.am
> index b985685..a7167d5 100644
> --- a/src/func_tests/Makefile.am
> +++ b/src/func_tests/Makefile.am
> @@ -5,7 +5,7 @@ include $(top_srcdir)/Makefile.rules
> include $(top_srcdir)/Makefile.dirs
>
> # General compilation flags
> -INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
> +INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
> AM_CFLAGS = -g -Wall -Wstrict-prototypes -Wimplicit-function-declaration
> AM_LDFLAGS = -lpthread
> LDADD = $(top_builddir)/src/lib/libsctp.la \
> @@ -27,6 +27,7 @@ PASSING_KERN_TESTS = \
> test_connectx \
> test_recvmsg \
> test_timetolive \
> + test_rtxtolive \
> test_sctp_sendrecvmsg \
> test_getname \
> test_tcp_style\
> @@ -55,6 +56,7 @@ PASSING_V6_KERN_TESTS = \
> test_inaddr_any_v6 \
> test_peeloff_v6 \
> test_timetolive_v6 \
> + test_rtxtolive_v6 \
> test_sctp_sendrecvmsg_v6 \
> test_getname_v6 \
> test_tcp_style_v6
> @@ -102,21 +104,22 @@ v6test: ${PASSING_V6_KERN_TESTS}
> @echo "Hoody hoo!"
>
> # Specifying the sources
> -test_assoc_abort_SOURCES = test_assoc_abort.c
> -test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
> -test_autoclose_SOURCES = test_autoclose.c
> -test_basic_SOURCES = test_basic.c
> -test_fragments_SOURCES = test_fragments.c
> -test_inaddr_any_SOURCES = test_inaddr_any.c
> -test_peeloff_SOURCES = test_peeloff.c
> -test_sockopt_SOURCES = test_sockopt.c
> -test_connect_SOURCES = test_connect.c
> -test_connectx_SOURCES = test_connectx.c
> -test_recvmsg_SOURCES = test_recvmsg.c
> +test_assoc_abort_SOURCES = test_assoc_abort.c
> +test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
> +test_autoclose_SOURCES = test_autoclose.c
> +test_basic_SOURCES = test_basic.c
> +test_fragments_SOURCES = test_fragments.c
> +test_inaddr_any_SOURCES = test_inaddr_any.c
> +test_peeloff_SOURCES = test_peeloff.c
> +test_sockopt_SOURCES = test_sockopt.c
> +test_connect_SOURCES = test_connect.c
> +test_connectx_SOURCES = test_connectx.c
> +test_recvmsg_SOURCES = test_recvmsg.c
> test_timetolive_SOURCES = test_timetolive.c
> +test_rtxtolive_SOURCES = test_rtxtolive.c
> test_sctp_sendrecvmsg_SOURCES = test_sctp_sendrecvmsg.c
> -test_getname_SOURCES = test_getname.c
> -test_tcp_style_SOURCES = test_tcp_style.c
> +test_getname_SOURCES = test_getname.c
> +test_tcp_style_SOURCES = test_tcp_style.c
>
> test_1_to_1_socket_bind_listen_SOURCES = test_1_to_1_socket_bind_listen.c
> test_1_to_1_accept_close_SOURCES = test_1_to_1_accept_close.c
> @@ -157,6 +160,9 @@ test_peeloff_v6_CFLAGS = ${V6FLAGS}
> test_timetolive_v6_SOURCES = test_timetolive.c
> test_timetolive_v6_CFLAGS = ${V6FLAGS}
>
> +test_rtxtolive_v6_SOURCES = test_rtxtolive.c
> +test_rtxtolive_v6_CFLAGS = ${V6FLAGS}
> +
> test_sctp_sendrecvmsg_v6_SOURCES = test_sctp_sendrecvmsg.c
> test_sctp_sendrecvmsg_v6_CFLAGS = ${V6FLAGS}
>
> diff --git a/src/func_tests/test_rtxtolive.c b/src/func_tests/test_rtxtolive.c
> new file mode 100644
> index 0000000..9aa03ad
> --- /dev/null
> +++ b/src/func_tests/test_rtxtolive.c
> @@ -0,0 +1,410 @@
> +/* SCTP kernel Implementation
> + * (C) Copyright IBM Corp. 2001, 2003
> + * Copyright (c) 1999-2000 Cisco, Inc.
> + * Copyright (c) 1999-2001 Motorola, Inc.
> + * Copyright (c) 2001 Intel Corp.
> + * Copyright (c) 2001 Nokia, Inc.
> + *
> + * The SCTP implementation is free software;
> + * you can redistribute it and/or modify it under the terms of
> + * the GNU General Public License as published by
> + * the Free Software Foundation; either version 2, or (at your option)
> + * any later version.
> + *
> + * The SCTP implementation is distributed in the hope that it
> + * will be useful, but WITHOUT ANY WARRANTY; without even the implied
> + * ************************
> + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> + * See the GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with GNU CC; see the file COPYING. If not, write to
> + * the Free Software Foundation, 59 Temple Place - Suite 330,
> + * Boston, MA 02111-1307, USA.
> + *
> + * Please send any bug reports or fixes you make to the
> + * email address(es):
> + * lksctp developers <lksctp-developers@lists.sourceforge.net>
> + *
> + * Or submit a bug report through the following website:
> + * http://www.sf.net/projects/lksctp
> + *
> + * Any bugs reported to us we will try to fix... any fixes shared will
> + * be incorporated into the next SCTP release.
> + *
> + * Written or modified by:
> + * Jon Grimm <jgrimm@us.ibm.com>
> + * Sridhar Samudrala <sri@us.ibm.com>
> + */
> +
> +/*
> + * This is a basic functional test for the SCTP kernel
> + * implementation of sndrcvinfo.sinfo_pr_value.
> + *
> + * 1) Create two sockets, the listening socket sets its RECVBUF small
> + * 2) Create a connection. Send enough data to the non-reading listener
> + * to fill the RCVBUF.
> + * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
> + * 6) Disable sinfo_pr_value on a message and send.
> + * 7) Wait sinfo_pr_value time.
> + * 8) Read out all the data at the receiver.
> + * 9) Make sure timed out message did not make it.
> + * 10) Make sure that the message with no timeout makes it to the receiver.
> + *
> + * Also test with SEND_FAILED notifications. Also, use a fragmented
> + * message so as to also exercise the SEND_FAILED of fragmentation
> + * code.
> + */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/types.h>
> +#include <sys/socket.h>
> +#include <sys/uio.h>
> +#include <netinet/in.h>
> +#include <sys/errno.h>
> +#include <errno.h>
> +#include <netinet/sctp.h>
> +#include <sctputil.h>
> +
> +char *TCID = __FILE__;
> +int TST_TOTAL = 6;
> +int TST_CNT = 0;
> +
> +/* This is the size of our RCVBUF */
> +#define SMALL_RCVBUF 3000
> +
> +/* MAX segment size */
> +#define SMALL_MAXSEG 100
> +
> +/* RWND_SLOP is the extra data that fills up the rwnd */
> +#define RWND_SLOP 100
> +static char *fillmsg = NULL;
> +static char *ttlmsg = "This should time out!\n";
> +static char *nottlmsg = "This should NOT time out!\n";
> +static char ttlfrag[SMALL_MAXSEG*3] = {0};
> +static char *message = "Hello world\n";
> +
> +int main(int argc, char *argv[])
> +{
> + int sk1, sk2;
> + sockaddr_storage_t loop1;
> + sockaddr_storage_t loop2;
> + struct iovec iov;
> + struct msghdr inmessage;
> + struct msghdr outmessage;
> + char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
> + char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
> + struct cmsghdr *cmsg;
> + struct sctp_sndrcvinfo *sinfo;
> + struct iovec out_iov;
> + int error;
> + int pf_class, af_family;
> + uint32_t ppid;
> + uint32_t stream;
> + sctp_assoc_t associd1, associd2;
> + struct sctp_assoc_change *sac;
> + struct sctp_event_subscribe subscribe;
> + char *big_buffer;
> + int offset;
> + struct sctp_send_failed *ssf;
> + int len; /* Really becomes 2xlen when set. */
> + int orig_len;
> + struct sctp_status gstatus;
> +
> + /* Rather than fflush() throughout the code, set stdout to
> + * be unbuffered.
> + */
> + setvbuf(stdout, NULL, _IONBF, 0);
> +
> + /* Set some basic values which depend on the address family. */
> +#if TEST_V6
> + pf_class = PF_INET6;
> + af_family = AF_INET6;
> +
> + loop1.v6.sin6_family = AF_INET6;
> + loop1.v6.sin6_addr = in6addr_loopback;
> + loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
> +
> + loop2.v6.sin6_family = AF_INET6;
> + loop2.v6.sin6_addr = in6addr_loopback;
> + loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
> +#else
> + pf_class = PF_INET;
> + af_family = AF_INET;
> +
> + loop1.v4.sin_family = AF_INET;
> + loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
> + loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
> +
> + loop2.v4.sin_family = AF_INET;
> + loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
> + loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
> +#endif /* TEST_V6 */
> +
> + /* Create the two endpoints which will talk to each other. */
> + sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
> + sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
> +
> + len = sizeof(int);
> + error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
> + &len);
> + if (error)
> + tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
> + strerror(errno));
> + /* Set the MAXSEG to something smallish. */
> + {
> + int val = SMALL_MAXSEG;
> + test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
> + }
> +
> + memset(&subscribe, 0, sizeof(subscribe));
> + subscribe.sctp_data_io_event = 1;
> + subscribe.sctp_association_event = 1;
> + subscribe.sctp_send_failure_event = 1;
> + test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
> + test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
> +
> + /* Bind these sockets to the test ports. */
> + test_bind(sk1, &loop1.sa, sizeof(loop1));
> + test_bind(sk2, &loop2.sa, sizeof(loop2));
> +
> + /*
> + * This code sets the associations RWND very small so we can
> + * fill it. It does this by manipulating the rcvbuf as follows:
> + * 1) Reduce the rcvbuf size on the socket
> + * 2) create an association so that we advertize rcvbuf/2 as
> + * our initial rwnd
> + * 3) raise the rcvbuf value so that we don't drop data wile
> + * receiving later data
> + */
> + len = SMALL_RCVBUF;
> + error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len,
> + sizeof(len));
> + if (error)
> + tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
> + strerror(errno));
> +
> + /* Mark sk2 as being able to accept new associations. */
> + test_listen(sk2, 1);
> +
> + /* Send the first message. This will create the association. */
> + outmessage.msg_name = &loop2;
> + outmessage.msg_namelen = sizeof(loop2);
> + outmessage.msg_iov = &out_iov;
> + outmessage.msg_iovlen = 1;
> + outmessage.msg_control = outcmsg;
> + outmessage.msg_controllen = sizeof(outcmsg);
> + outmessage.msg_flags = 0;
> + cmsg = CMSG_FIRSTHDR(&outmessage);
> + cmsg->cmsg_level = IPPROTO_SCTP;
> + cmsg->cmsg_type = SCTP_SNDRCV;
> + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
> + outmessage.msg_controllen = cmsg->cmsg_len;
> + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
> + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
> + ppid = rand(); /* Choose an arbitrary value. */
> + stream = 1;
> + sinfo->sinfo_ppid = ppid;
> + sinfo->sinfo_stream = stream;
> + outmessage.msg_iov->iov_base = message;
> + outmessage.msg_iov->iov_len = strlen(message) + 1;
> + test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
> +
> + /* Initialize inmessage for all receives. */
> + big_buffer = test_malloc(REALLY_BIG);
> + memset(&inmessage, 0, sizeof(inmessage));
> + iov.iov_base = big_buffer;
> + iov.iov_len = REALLY_BIG;
> + inmessage.msg_iov = &iov;
> + inmessage.msg_iovlen = 1;
> + inmessage.msg_control = incmsg;
> +
> + /* Get the communication up message on sk2. */
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
> + test_check_msg_notification(&inmessage, error,
> + sizeof(struct sctp_assoc_change),
> + SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
> + sac = (struct sctp_assoc_change *)iov.iov_base;
> + associd2 = sac->sac_assoc_id;
> +
> + /* Get the communication up message on sk1. */
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
> + test_check_msg_notification(&inmessage, error,
> + sizeof(struct sctp_assoc_change),
> + SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
> + sac = (struct sctp_assoc_change *)iov.iov_base;
> + associd1 = sac->sac_assoc_id;
> +
> + /* restore the rcvbuffer size for the receiving socket */
> + error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
> + sizeof(orig_len));
> +
> + if (error)
> + tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
> + strerror(errno));
> +
> + /* Get the first data message which was sent. */
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
> + test_check_msg_data(&inmessage, error, strlen(message) + 1,
> + MSG_EOR, stream, ppid);
> +
> + /* Figure out how big to make our fillmsg */
> + len = sizeof(struct sctp_status);
> + memset(&gstatus,0,sizeof(struct sctp_status));
> + gstatus.sstat_assoc_id = associd1;
> + error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
> +
> + if (error)
> + tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
> + strerror(errno));
> + tst_resm(TINFO, "Creating fillmsg of size %d",
> + gstatus.sstat_rwnd+RWND_SLOP);
> + fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
> +
> + /* Send a fillmsg */
> + outmessage.msg_controllen = sizeof(outcmsg);
> + outmessage.msg_flags = 0;
> + cmsg = CMSG_FIRSTHDR(&outmessage);
> + cmsg->cmsg_level = IPPROTO_SCTP;
> + cmsg->cmsg_type = SCTP_SNDRCV;
> + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
> + outmessage.msg_controllen = cmsg->cmsg_len;
> + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
> + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
> + ppid++;
> + stream++;
> + sinfo->sinfo_ppid = ppid;
> + sinfo->sinfo_stream = stream;
> + memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
> + fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
> + outmessage.msg_iov->iov_base = fillmsg;
> + outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP;
> + outmessage.msg_name = NULL;
> + outmessage.msg_namelen = 0;
> + sinfo->sinfo_assoc_id = associd1;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
> + sinfo->sinfo_pr_value = 0;
> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
> + gstatus.sstat_rwnd+RWND_SLOP);
> +
> + /* Now send the message with timeout. */
> + sinfo->sinfo_ppid = ppid;
> + sinfo->sinfo_stream = stream;
> + outmessage.msg_iov->iov_base = ttlmsg;
> + outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1;
> + outmessage.msg_name = NULL;
> + outmessage.msg_namelen = 0;
> + sinfo->sinfo_assoc_id = associd1;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
> + sinfo->sinfo_pr_value = 2;
> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
> +
> + tst_resm(TPASS, "Send a message with timeout");
> +
> + /* Next send a message with no timeout. */
> + sinfo->sinfo_ppid = ppid;
> + sinfo->sinfo_stream = stream;
> + outmessage.msg_iov->iov_base = nottlmsg;
> + outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1;
> + outmessage.msg_name = NULL;
> + outmessage.msg_namelen = 0;
> + sinfo->sinfo_assoc_id = associd1;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
> + sinfo->sinfo_pr_value = 0;
> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
> +
> + tst_resm(TPASS, "Send a message with no timeout");
> +
> + /* And finally a fragmented message that will time out. */
> + sinfo->sinfo_ppid = ppid;
> + sinfo->sinfo_stream = stream;
> + memset(ttlfrag, '0', sizeof(ttlfrag));
> + ttlfrag[sizeof(ttlfrag)-1] = '\0';
> + outmessage.msg_iov->iov_base = ttlfrag;
> + outmessage.msg_iov->iov_len = sizeof(ttlfrag);
> + outmessage.msg_name = NULL;
> + outmessage.msg_namelen = 0;
> + sinfo->sinfo_assoc_id = associd1;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
> + sinfo->sinfo_pr_value = 2;
> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
> +
> + tst_resm(TPASS, "Send a fragmented message with timeout");
> +
> + /* Sleep waiting for the message to time out. */
> + tst_resm(TINFO, " ** SLEEPING for 3 seconds **");
> + sleep(3);
> +
> + /* Read the fillmsg snuck in between the ttl'd messages. */
> + do {
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
> + } while (!(inmessage.msg_flags & MSG_EOR));
> +
> + /* Now get the message that did NOT time out. */
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
> + test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1,
> + MSG_EOR, stream, ppid);
> + if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1))
> + tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!");
> +
> + tst_resm(TPASS, "Receive message with no timeout");
> +
> + /* Get the SEND_FAILED notification for the message that DID
> + * time out.
> + */
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
> + test_check_msg_notification(&inmessage, error,
> + sizeof(struct sctp_send_failed) +
> + strlen(ttlmsg) + 1,
> + SCTP_SEND_FAILED, 0);
> + ssf = (struct sctp_send_failed *)iov.iov_base;
> + if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
> + tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
> +
> + tst_resm(TPASS, "Receive SEND_FAILED for message with timeout");
> +
> + /* Get the SEND_FAILED notification for the fragmented message that
> + * DID time out.
> + */
> + offset = 0;
> + do {
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
> + test_check_msg_notification(&inmessage, error,
> + sizeof(struct sctp_send_failed) +
> + SMALL_MAXSEG,
> + SCTP_SEND_FAILED, 0);
> + ssf = (struct sctp_send_failed *)iov.iov_base;
> + if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
> + SMALL_MAXSEG))
> + tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
> + offset += SMALL_MAXSEG;
> + } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */
> +
> + tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with "
> + "timeout");
> +
> + /* Shut down the link. */
> + close(sk1);
> +
> + /* Get the shutdown complete notification. */
> + inmessage.msg_controllen = sizeof(incmsg);
> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
> + test_check_msg_notification(&inmessage, error,
> + sizeof(struct sctp_assoc_change),
> + SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
> +
> + close(sk2);
> +
> + /* Indicate successful completion. */
> + return 0;
> +}
> diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
> index c275e45..aaa56e9 100644
> --- a/src/func_tests/test_sctp_sendrecvmsg.c
> +++ b/src/func_tests/test_sctp_sendrecvmsg.c
> @@ -243,7 +243,7 @@ int main(int argc, char *argv[])
> /* Now send a message that will timeout. */
> test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
> (struct sockaddr *)&loop2, sizeof(loop2),
> - ppid, 0, stream, 2000, 0);
> + ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
>
> tst_resm(TPASS, "sctp_sendmsg with ttl");
>
> @@ -259,7 +259,7 @@ int main(int argc, char *argv[])
> ttlfrag[sizeof(ttlfrag)-1] = '\0';
> test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
> (struct sockaddr *)&loop2, sizeof(loop2),
> - ppid, 0, stream, 2000, 0);
> + ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
>
> tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
>
> @@ -335,7 +335,8 @@ int main(int argc, char *argv[])
> snd_sinfo.sinfo_ppid = rand();
> snd_sinfo.sinfo_flags = 0;
> snd_sinfo.sinfo_stream = 2;
> - snd_sinfo.sinfo_timetolive = 0;
> + snd_sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
> + snd_sinfo.sinfo_pr_value = 0;
> snd_sinfo.sinfo_assoc_id = associd1;
> test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
> MSG_NOSIGNAL);
> diff --git a/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
> index d9bdf1b..dc66722 100644
> --- a/src/func_tests/test_timetolive.c
> +++ b/src/func_tests/test_timetolive.c
> @@ -39,14 +39,14 @@
>
> /*
> * This is a basic functional test for the SCTP kernel
> - * implementation of sndrcvinfo.sinfo_timetolive.
> + * implementation of sndrcvinfo.sinfo_pr_value.
> *
> * 1) Create two sockets, the listening socket sets its RECVBUF small
> * 2) Create a connection. Send enough data to the non-reading listener
> * to fill the RCVBUF.
> - * 5) Set sinfo_timetolive on a message and send.
> - * 6) Disable sinfo_timetolive on a message and send.
> - * 7) Wait sinfo_timetolive.
> + * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
> + * 6) Disable sinfo_pr_value on a message and send.
> + * 7) Wait sinfo_pr_value time.
> * 8) Read out all the data at the receiver.
> * 9) Make sure timed out message did not make it.
> * 10) Make sure that the message with no timeout makes it to the receiver.
> @@ -288,7 +288,8 @@ int main(int argc, char *argv[])
> outmessage.msg_name = NULL;
> outmessage.msg_namelen = 0;
> sinfo->sinfo_assoc_id = associd1;
> - sinfo->sinfo_timetolive = 0;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
> + sinfo->sinfo_pr_value = 0;
> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
> gstatus.sstat_rwnd+RWND_SLOP);
>
> @@ -300,7 +301,8 @@ int main(int argc, char *argv[])
> outmessage.msg_name = NULL;
> outmessage.msg_namelen = 0;
> sinfo->sinfo_assoc_id = associd1;
> - sinfo->sinfo_timetolive = 2000;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
> + sinfo->sinfo_pr_value = 2000;
> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
>
> tst_resm(TPASS, "Send a message with timeout");
> @@ -313,7 +315,8 @@ int main(int argc, char *argv[])
> outmessage.msg_name = NULL;
> outmessage.msg_namelen = 0;
> sinfo->sinfo_assoc_id = associd1;
> - sinfo->sinfo_timetolive = 0;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
> + sinfo->sinfo_pr_value = 0;
> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
>
> tst_resm(TPASS, "Send a message with no timeout");
> @@ -328,7 +331,8 @@ int main(int argc, char *argv[])
> outmessage.msg_name = NULL;
> outmessage.msg_namelen = 0;
> sinfo->sinfo_assoc_id = associd1;
> - sinfo->sinfo_timetolive = 2000;
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
> + sinfo->sinfo_pr_value = 2000;
> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
>
> tst_resm(TPASS, "Send a fragmented message with timeout");
> diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h
> index ae557a5..5a6cea2 100644
> --- a/src/include/netinet/sctp.h
> +++ b/src/include/netinet/sctp.h
> @@ -184,9 +184,10 @@ struct sctp_sndrcvinfo {
> __u16 sinfo_stream;
> __u16 sinfo_ssn;
> __u16 sinfo_flags;
> + __u16 sinfo_pr_policy;
> __u32 sinfo_ppid;
> __u32 sinfo_context;
> - __u32 sinfo_timetolive;
> + __u32 sinfo_pr_value;
> __u32 sinfo_tsn;
> __u32 sinfo_cumtsn;
> sctp_assoc_t sinfo_assoc_id;
> @@ -200,12 +201,25 @@ struct sctp_sndrcvinfo {
> */
>
> enum sctp_sinfo_flags {
> - SCTP_UNORDERED = 1, /* Send/receive message unordered. */
> - SCTP_ADDR_OVER = 2, /* Override the primary destination. */
> - SCTP_ABORT=4, /* Send an ABORT message to the peer. */
> - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
> + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
> + SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
> + SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
> + SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
> };
>
> +/*
> + * sinfo_pr_policy: 16 bits (unsigned integer)
> + *
> + * This field may contain the partial reliability used to
> + * send the message.
> + */
> +
> +enum sctp_sinfo_pr_policy {
> + SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
> + SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliable */
> + SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliable */
> + SCTP_PR_SCTP_RTX = 0x0003, /* Retransmist partial reliable */
> +};
>
> typedef union {
> __u8 raw;
> @@ -816,7 +830,7 @@ int sctp_freeladdrs(struct sockaddr *addrs);
> */
> int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
> socklen_t tolen, uint32_t ppid, uint32_t flags,
> - uint16_t stream_no, uint32_t timetolive, uint32_t context);
> + uint16_t stream_no, uint32_t pr_value, uint32_t context);
>
> /* This library function assist the user with sending a message without
> * dealing directly with the CMSG header.
> diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
> index 1de592d..a674646 100644
> --- a/src/lib/sendmsg.c
> +++ b/src/lib/sendmsg.c
> @@ -31,7 +31,7 @@
> int
> sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
> socklen_t tolen, uint32_t ppid, uint32_t flags,
> - uint16_t stream_no, uint32_t timetolive, uint32_t context)
> + uint16_t stream_no, uint32_t pr_value, uint32_t context)
> {
> struct msghdr outmsg;
> struct iovec iov;
> @@ -61,9 +61,22 @@ sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
> sinfo->sinfo_ppid = ppid;
> sinfo->sinfo_flags = flags;
> sinfo->sinfo_stream = stream_no;
> - sinfo->sinfo_timetolive = timetolive;
> sinfo->sinfo_context = context;
>
> + sinfo->sinfo_pr_policy = sinfo->sinfo_flags & 0xff;
> + sinfo->sinfo_pr_value = pr_value;
> +
> + printf("sinfo_flags: %x sinfo_pr_policy: %d sinfo_pr_value: %d\n",
> + sinfo->sinfo_flags, sinfo->sinfo_pr_policy, sinfo->sinfo_pr_value);
> +
> + /* If we get an invalid sinfo_pr_policy force it to
> + * SCTP_PR_SCTP_NONE or shall we better fail and set a
> + * EINVAL error??
> + */
> +
> + if(sinfo->sinfo_pr_policy > SCTP_PR_SCTP_RTX)
> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
> +
> return sendmsg(s, &outmsg, 0);
> }
>
> diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
> index 347c91b..0afbc36 100644
> --- a/src/testlib/sctputil.h
> +++ b/src/testlib/sctputil.h
> @@ -270,11 +270,11 @@ static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
> static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
> struct sockaddr *to, socklen_t tolen,
> uint32_t ppid, uint32_t flags,
> - uint16_t stream_no, uint32_t timetolive,
> + uint16_t stream_no, uint32_t pr_value,
> uint32_t context)
> {
> int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
> - timetolive, context);
> + pr_value, context);
> if (len != error)
> tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
> error, errno);
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] Replace timetolive with pr_policy and pr_value
2008-12-03 1:59 [PATCH] Replace timetolive with pr_policy and pr_value Horacio Sanson
` (2 preceding siblings ...)
2008-12-15 15:55 ` Vlad Yasevich
@ 2008-12-16 7:53 ` Horacio Sanson
2008-12-16 14:33 ` Vlad Yasevich
4 siblings, 0 replies; 6+ messages in thread
From: Horacio Sanson @ 2008-12-16 7:53 UTC (permalink / raw)
To: linux-sctp
On Tue, Dec 16, 2008 at 12:55 AM, Vlad Yasevich
<vladislav.yasevich@hp.com> wrote:
>> I created a new patch set that fixes the SCTP_PR_SCTP_RTX partial
>> reliability that was not working and added a test program to test it.
>> Again all v4tests and v6tests pass including my own tests.
>>
>> This includes the previous patches so the previous ones should be
>> ignored. But no one seems to be looking at my patches so I think there
>> should be no problems anyway :( .
>>
>>
>
> I am looking, I am just busy with other things as well. Please be patient.
>
Thanks, I really appreciate the feedback.
> As a first step that will make review much easier, please get rid of the whitespace
> changes that show up. That will improve the readability of the patches.
>
I tried my best here but seems I did it all wrong. I though that using
a command like "git apply --check --whitespaces=error-all" was enough
to make sure no trailing spaces or spaces before tabs were present.
Seems this is not the case as the command gives no errors even though
there are in fact white spaces all over the place. Will check again.
> Also, please separate the patches into separate e-mails. Look at git-send-email
> and git-format-patch for more information.
>
Will rewrite my patches again trying to split the changes in smaller
and more concise steps.
> Thanks
> -vlad
>
>>
>>
>>
>> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
>> index 9661d7b..ffda4c5 100644
>> --- a/include/net/sctp/structs.h
>> +++ b/include/net/sctp/structs.h
>> @@ -208,7 +208,7 @@ extern struct sctp_globals {
>>
>> /* Lock that protects the local_addr_list writers */
>> spinlock_t addr_list_lock;
>> -
>> +
>> /* Flag to indicate if addip is enabled. */
>> int addip_enable;
>> int addip_noauth_enable;
>> @@ -282,7 +282,8 @@ struct sctp_sock {
>> __u32 default_ppid;
>> __u16 default_flags;
>> __u32 default_context;
>> - __u32 default_timetolive;
>> + __u16 default_pr_policy;
>> + __u32 default_pr_value;
>
> Please don't add any memory holes when adding new entries to the structure.
Could you please elaborate in this comment?? Has this something to do
with memory alignment issues of some sort? How can I avoid this memory
hole you mention??
thanks,
Horacio
>
>> __u32 default_rcv_context;
>> int max_burst;
>>
>> @@ -390,7 +391,7 @@ struct sctp_cookie {
>> /* This holds the originating address of the INIT packet. */
>> union sctp_addr peer_addr;
>>
>> - /* IG Section 2.35.3
>> + /* IG Section 2.35.3
>> * Include the source port of the INIT-ACK
>> */
>> __u16 my_port;
>> @@ -398,7 +399,7 @@ struct sctp_cookie {
>> __u8 prsctp_capable;
>>
>> /* Padding for future use */
>> - __u8 padding;
>> + __u8 padding;
>
> White space? Please limit the scope of your patches.
>
>>
>> __u32 adaptation_ind;
>>
>> @@ -512,12 +513,12 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
>> }
>>
>> /* Skip over this ssn and all below. */
>> -static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
>> +static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
>> __u16 ssn)
>> {
>> stream->ssn[id] = ssn+1;
>> }
>> -
>> +
>
> More whitespace?
>
>> /*
>> * Pointers to address related SCTP functions.
>> * (i.e. things that depend on the address family.)
>> @@ -575,7 +576,7 @@ struct sctp_af {
>> union sctp_addr_param *,
>> __be16 port, int iif);
>> int (*to_addr_param) (const union sctp_addr *,
>> - union sctp_addr_param *);
>> + union sctp_addr_param *);
>
> Again?
>
>> int (*addr_valid) (union sctp_addr *,
>> struct sctp_sock *,
>> const struct sk_buff *);
>> @@ -626,13 +627,15 @@ struct sctp_datamsg {
>> struct list_head track;
>> /* Reference counting. */
>> atomic_t refcnt;
>> +
>> + /* Policy used to determine expired messages */
>> + unsigned long expires_policy;
>> /* When is this message no longer interesting to the peer? */
>> unsigned long expires_at;
>> /* Did the messenge fail to send? */
>> int send_error;
>> char send_failed;
>> /* Control whether chunks from this message can be abandoned. */
>> - char can_abandon;
>> };
>>
>> struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
>> @@ -1339,7 +1342,7 @@ struct sctp_endpoint {
>> * on every receive.
>> */
>> __u8 *digest;
>> -
>> +
>
> Again? I am done at this point!!!
>
>> /* sendbuf acct. policy. */
>> __u32 sndbuf_policy;
>>
>> @@ -1759,9 +1762,10 @@ struct sctp_association {
>> /* Default send parameters. */
>> __u16 default_stream;
>> __u16 default_flags;
>> + __u16 default_pr_policy;
>> __u32 default_ppid;
>> __u32 default_context;
>> - __u32 default_timetolive;
>> + __u32 default_pr_value;
>>
>> /* Default receive parameters */
>> __u32 default_rcv_context;
>> diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
>> index f205b10..74c0aba 100644
>> --- a/include/net/sctp/user.h
>> +++ b/include/net/sctp/user.h
>> @@ -71,7 +71,7 @@ enum sctp_optname {
>> #define SCTP_NODELAY SCTP_NODELAY
>> SCTP_AUTOCLOSE,
>> #define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
>> - SCTP_SET_PEER_PRIMARY_ADDR,
>> + SCTP_SET_PEER_PRIMARY_ADDR,
>> #define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
>> SCTP_PRIMARY_ADDR,
>> #define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
>> @@ -120,7 +120,7 @@ enum sctp_optname {
>> #define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
>>
>>
>> - /* Internal Socket Options. Some of the sctp library functions are
>> + /* Internal Socket Options. Some of the sctp library functions are
>> * implemented using these socket options.
>> */
>> SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
>> @@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
>> __u16 sinfo_stream;
>> __u16 sinfo_ssn;
>> __u16 sinfo_flags;
>> + __u16 sinfo_pr_policy;
>> __u32 sinfo_ppid;
>> __u32 sinfo_context;
>> - __u32 sinfo_timetolive;
>> + __u32 sinfo_pr_value;
>> __u32 sinfo_tsn;
>> __u32 sinfo_cumtsn;
>> sctp_assoc_t sinfo_assoc_id;
>> @@ -199,12 +200,25 @@ struct sctp_sndrcvinfo {
>> */
>>
>> enum sctp_sinfo_flags {
>> - SCTP_UNORDERED = 1, /* Send/receive message unordered. */
>> - SCTP_ADDR_OVER = 2, /* Override the primary destination. */
>> - SCTP_ABORT=4, /* Send an ABORT message to the peer. */
>> - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
>> + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. (0x0200) */
>> + SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
>> + SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
>> + SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
>> };
>>
>> +/*
>> + * sinfo_pr_policy: 16 bits (unsigned integer)
>> + *
>> + * This field may contain the partial reliability used to
>> + * send the message.
>> + */
>> +
>> +enum sctp_sinfo_pr_policy {
>> + SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
>> + SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliability */
>> + SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliability (EXPERIMENTAL) */
>> + SCTP_PR_SCTP_RTX = 0x0003, /* Retransmis partial reliability (EXPERIMENTAL) */
>> +};
>>
>> typedef union {
>> __u8 raw;
>> @@ -479,7 +493,7 @@ typedef enum sctp_sn_error {
>> *
>> * The protocol parameters used to initialize and bound retransmission
>> * timeout (RTO) are tunable. See [SCTP] for more information on how
>> - * these parameters are used in RTO calculation.
>> + * these parameters are used in RTO calculation.
>> */
>> struct sctp_rtoinfo {
>> sctp_assoc_t srto_assoc_id;
>> @@ -717,9 +731,9 @@ struct sctp_authchunks {
>>
>> /*
>> * 8.3, 8.5 get all peer/local addresses in an association.
>> - * This parameter struct is used by SCTP_GET_PEER_ADDRS and
>> + * This parameter struct is used by SCTP_GET_PEER_ADDRS and
>> * SCTP_GET_LOCAL_ADDRS socket options used internally to implement
>> - * sctp_getpaddrs() and sctp_getladdrs() API.
>> + * sctp_getpaddrs() and sctp_getladdrs() API.
>> */
>> struct sctp_getaddrs_old {
>> sctp_assoc_t assoc_id;
>>
>>
>>
>> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
>> index f4b2304..c178139 100644
>> --- a/net/sctp/associola.c
>> +++ b/net/sctp/associola.c
>> @@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
>> asoc->default_ppid = sp->default_ppid;
>> asoc->default_flags = sp->default_flags;
>> asoc->default_context = sp->default_context;
>> - asoc->default_timetolive = sp->default_timetolive;
>> + asoc->default_pr_policy = sp->default_pr_policy;
>> + asoc->default_pr_value = sp->default_pr_value;
>> asoc->default_rcv_context = sp->default_rcv_context;
>>
>> /* AUTH related initializations */
>> diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
>> index 1748ef9..4cdfe49 100644
>> --- a/net/sctp/chunk.c
>> +++ b/net/sctp/chunk.c
>> @@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
>> atomic_set(&msg->refcnt, 1);
>> msg->send_failed = 0;
>> msg->send_error = 0;
>> - msg->can_abandon = 0;
>> + msg->expires_policy = SCTP_PR_SCTP_NONE;
>> msg->expires_at = 0;
>> INIT_LIST_HEAD(&msg->chunks);
>> }
>> @@ -170,13 +170,26 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
>> /* Note: Calculate this outside of the loop, so that all fragments
>> * have the same expiration.
>> */
>> - if (sinfo->sinfo_timetolive) {
>> - /* sinfo_timetolive is in milliseconds */
>> - msg->expires_at = jiffies +
>> - msecs_to_jiffies(sinfo->sinfo_timetolive);
>> - msg->can_abandon = 1;
>> - SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
>> - __func__, msg, msg->expires_at, jiffies);
>> +
>> + msg->expires_policy = sinfo->sinfo_pr_policy;
>> +
>> + if(msg->expires_policy) {
>> + switch(msg->expires_policy) {
>> + case SCTP_PR_SCTP_TTL:
>> + /* sinfo_timetolive is in milliseconds */
>> + msg->expires_at = jiffies +
>> + msecs_to_jiffies(sinfo->sinfo_pr_value);
>> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
>> + __func__, msg, msg->expires_at, jiffies);
>> + break;
>> + case SCTP_PR_SCTP_BUF:
>> + break;
>> + case SCTP_PR_SCTP_RTX:
>> + msg->expires_at = sinfo->sinfo_pr_value;
>> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_after: %ld retransmissions \n",
>> + __func__, msg, msg->expires_at);
>> + break;
>> + }
>> }
>>
>> max = asoc->frag_point;
>> @@ -291,11 +304,23 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
>> {
>> struct sctp_datamsg *msg = chunk->msg;
>>
>> - if (!msg->can_abandon)
>> + if (!msg->expires_policy)
>> return 0;
>>
>> - if (time_after(jiffies, msg->expires_at))
>> - return 1;
>> + switch(msg->expires_policy) {
>> + case SCTP_PR_SCTP_TTL:
>> + if (time_after(jiffies, msg->expires_at))
>> + return 1;
>> + case SCTP_PR_SCTP_BUF:
>> + /* TODO: Implement this */
>> + return 0;
>> + case SCTP_PR_SCTP_RTX:
>> + if(--msg->expires_at <= 0) {
>> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld EXPIRED!!\n",
>> + __func__, msg, msg->expires_at);
>> + return 1;
>> + }
>> + }
>>
>> return 0;
>> }
>> diff --git a/net/sctp/output.c b/net/sctp/output.c
>> index c3f417f..b344a9d 100644
>> --- a/net/sctp/output.c
>> +++ b/net/sctp/output.c
>> @@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
>> asoc->peer.rwnd = rwnd;
>> /* Has been accepted for transmission. */
>> if (!asoc->peer.prsctp_capable)
>> - chunk->msg->can_abandon = 0;
>> + chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
>>
>> finish:
>> return retval;
>> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
>> index a1b9045..0dfc137 100644
>> --- a/net/sctp/socket.c
>> +++ b/net/sctp/socket.c
>> @@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
>> default_sinfo.sinfo_flags = asoc->default_flags;
>> default_sinfo.sinfo_ppid = asoc->default_ppid;
>> default_sinfo.sinfo_context = asoc->default_context;
>> - default_sinfo.sinfo_timetolive = asoc->default_timetolive;
>> + default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
>> + default_sinfo.sinfo_pr_value = asoc->default_pr_value;
>> default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
>> sinfo = &default_sinfo;
>> }
>> @@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
>> * in to this call the sctp_sndrcvinfo structure defined in Section
>> * 5.2.2) The input parameters accepted by this call include
>> * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
>> - * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
>> + * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
>> * to this call if the caller is using the UDP model.
>> */
>> static int sctp_setsockopt_default_send_param(struct sock *sk,
>> @@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
>> asoc->default_flags = info.sinfo_flags;
>> asoc->default_ppid = info.sinfo_ppid;
>> asoc->default_context = info.sinfo_context;
>> - asoc->default_timetolive = info.sinfo_timetolive;
>> + asoc->default_pr_policy = info.sinfo_pr_policy;
>> + asoc->default_pr_value = info.sinfo_pr_value;
>> } else {
>> sp->default_stream = info.sinfo_stream;
>> sp->default_flags = info.sinfo_flags;
>> sp->default_ppid = info.sinfo_ppid;
>> sp->default_context = info.sinfo_context;
>> - sp->default_timetolive = info.sinfo_timetolive;
>> + sp->default_pr_policy = info.sinfo_pr_policy;
>> + sp->default_pr_value = info.sinfo_pr_value;
>> }
>>
>> return 0;
>> @@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
>> sp->default_ppid = 0;
>> sp->default_flags = 0;
>> sp->default_context = 0;
>> - sp->default_timetolive = 0;
>> + sp->default_pr_policy = 0;
>> + sp->default_pr_value = 0;
>>
>> sp->default_rcv_context = 0;
>> sp->max_burst = sctp_max_burst;
>> @@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
>> * in to this call the sctp_sndrcvinfo structure defined in Section
>> * 5.2.2) The input parameters accepted by this call include
>> * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
>> - * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
>> + * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
>> * to this call if the caller is using the UDP model.
>> *
>> * For getsockopt, it get the default sctp_sndrcvinfo structure.
>> @@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
>> info.sinfo_flags = asoc->default_flags;
>> info.sinfo_ppid = asoc->default_ppid;
>> info.sinfo_context = asoc->default_context;
>> - info.sinfo_timetolive = asoc->default_timetolive;
>> + info.sinfo_pr_policy = asoc->default_pr_policy;
>> + info.sinfo_pr_value = asoc->default_pr_value;
>> } else {
>> info.sinfo_stream = sp->default_stream;
>> info.sinfo_flags = sp->default_flags;
>> info.sinfo_ppid = sp->default_ppid;
>> info.sinfo_context = sp->default_context;
>> - info.sinfo_timetolive = sp->default_timetolive;
>> + info.sinfo_pr_policy = sp->default_pr_policy;
>> + info.sinfo_pr_value = sp->default_pr_value;
>> }
>>
>> if (put_user(len, optlen))
>> @@ -6107,10 +6113,17 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
>> (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>>
>> /* Minimally, validate the sinfo_flags. */
>> +
>> + /* TODO this validation does not work with the new
>> + * SCTP_PR_SCTP_XXX flags
>> + */
>> +
>> + /*
>> if (cmsgs->info->sinfo_flags &
>> ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
>> SCTP_ABORT | SCTP_EOF))
>> return -EINVAL;
>> + */
>> break;
>>
>> default:
>> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
>> index 5f186ca..2c6f111 100644
>> --- a/net/sctp/ulpevent.c
>> +++ b/net/sctp/ulpevent.c
>> @@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
>> sinfo.sinfo_context = event->asoc->default_rcv_context;
>>
>> /* These fields are not used while receiving. */
>> - sinfo.sinfo_timetolive = 0;
>> + sinfo.sinfo_pr_policy = 0;
>> + sinfo.sinfo_pr_value = 0;
>>
>> put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
>> sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
>>
>>
>>
>> diff --git a/src/func_tests/Makefile.am b/src/func_tests/Makefile.am
>> index b985685..a7167d5 100644
>> --- a/src/func_tests/Makefile.am
>> +++ b/src/func_tests/Makefile.am
>> @@ -5,7 +5,7 @@ include $(top_srcdir)/Makefile.rules
>> include $(top_srcdir)/Makefile.dirs
>>
>> # General compilation flags
>> -INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
>> +INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
>> AM_CFLAGS = -g -Wall -Wstrict-prototypes -Wimplicit-function-declaration
>> AM_LDFLAGS = -lpthread
>> LDADD = $(top_builddir)/src/lib/libsctp.la \
>> @@ -27,6 +27,7 @@ PASSING_KERN_TESTS = \
>> test_connectx \
>> test_recvmsg \
>> test_timetolive \
>> + test_rtxtolive \
>> test_sctp_sendrecvmsg \
>> test_getname \
>> test_tcp_style\
>> @@ -55,6 +56,7 @@ PASSING_V6_KERN_TESTS = \
>> test_inaddr_any_v6 \
>> test_peeloff_v6 \
>> test_timetolive_v6 \
>> + test_rtxtolive_v6 \
>> test_sctp_sendrecvmsg_v6 \
>> test_getname_v6 \
>> test_tcp_style_v6
>> @@ -102,21 +104,22 @@ v6test: ${PASSING_V6_KERN_TESTS}
>> @echo "Hoody hoo!"
>>
>> # Specifying the sources
>> -test_assoc_abort_SOURCES = test_assoc_abort.c
>> -test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
>> -test_autoclose_SOURCES = test_autoclose.c
>> -test_basic_SOURCES = test_basic.c
>> -test_fragments_SOURCES = test_fragments.c
>> -test_inaddr_any_SOURCES = test_inaddr_any.c
>> -test_peeloff_SOURCES = test_peeloff.c
>> -test_sockopt_SOURCES = test_sockopt.c
>> -test_connect_SOURCES = test_connect.c
>> -test_connectx_SOURCES = test_connectx.c
>> -test_recvmsg_SOURCES = test_recvmsg.c
>> +test_assoc_abort_SOURCES = test_assoc_abort.c
>> +test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
>> +test_autoclose_SOURCES = test_autoclose.c
>> +test_basic_SOURCES = test_basic.c
>> +test_fragments_SOURCES = test_fragments.c
>> +test_inaddr_any_SOURCES = test_inaddr_any.c
>> +test_peeloff_SOURCES = test_peeloff.c
>> +test_sockopt_SOURCES = test_sockopt.c
>> +test_connect_SOURCES = test_connect.c
>> +test_connectx_SOURCES = test_connectx.c
>> +test_recvmsg_SOURCES = test_recvmsg.c
>> test_timetolive_SOURCES = test_timetolive.c
>> +test_rtxtolive_SOURCES = test_rtxtolive.c
>> test_sctp_sendrecvmsg_SOURCES = test_sctp_sendrecvmsg.c
>> -test_getname_SOURCES = test_getname.c
>> -test_tcp_style_SOURCES = test_tcp_style.c
>> +test_getname_SOURCES = test_getname.c
>> +test_tcp_style_SOURCES = test_tcp_style.c
>>
>> test_1_to_1_socket_bind_listen_SOURCES = test_1_to_1_socket_bind_listen.c
>> test_1_to_1_accept_close_SOURCES = test_1_to_1_accept_close.c
>> @@ -157,6 +160,9 @@ test_peeloff_v6_CFLAGS = ${V6FLAGS}
>> test_timetolive_v6_SOURCES = test_timetolive.c
>> test_timetolive_v6_CFLAGS = ${V6FLAGS}
>>
>> +test_rtxtolive_v6_SOURCES = test_rtxtolive.c
>> +test_rtxtolive_v6_CFLAGS = ${V6FLAGS}
>> +
>> test_sctp_sendrecvmsg_v6_SOURCES = test_sctp_sendrecvmsg.c
>> test_sctp_sendrecvmsg_v6_CFLAGS = ${V6FLAGS}
>>
>> diff --git a/src/func_tests/test_rtxtolive.c b/src/func_tests/test_rtxtolive.c
>> new file mode 100644
>> index 0000000..9aa03ad
>> --- /dev/null
>> +++ b/src/func_tests/test_rtxtolive.c
>> @@ -0,0 +1,410 @@
>> +/* SCTP kernel Implementation
>> + * (C) Copyright IBM Corp. 2001, 2003
>> + * Copyright (c) 1999-2000 Cisco, Inc.
>> + * Copyright (c) 1999-2001 Motorola, Inc.
>> + * Copyright (c) 2001 Intel Corp.
>> + * Copyright (c) 2001 Nokia, Inc.
>> + *
>> + * The SCTP implementation is free software;
>> + * you can redistribute it and/or modify it under the terms of
>> + * the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2, or (at your option)
>> + * any later version.
>> + *
>> + * The SCTP implementation is distributed in the hope that it
>> + * will be useful, but WITHOUT ANY WARRANTY; without even the implied
>> + * ************************
>> + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>> + * See the GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with GNU CC; see the file COPYING. If not, write to
>> + * the Free Software Foundation, 59 Temple Place - Suite 330,
>> + * Boston, MA 02111-1307, USA.
>> + *
>> + * Please send any bug reports or fixes you make to the
>> + * email address(es):
>> + * lksctp developers <lksctp-developers@lists.sourceforge.net>
>> + *
>> + * Or submit a bug report through the following website:
>> + * http://www.sf.net/projects/lksctp
>> + *
>> + * Any bugs reported to us we will try to fix... any fixes shared will
>> + * be incorporated into the next SCTP release.
>> + *
>> + * Written or modified by:
>> + * Jon Grimm <jgrimm@us.ibm.com>
>> + * Sridhar Samudrala <sri@us.ibm.com>
>> + */
>> +
>> +/*
>> + * This is a basic functional test for the SCTP kernel
>> + * implementation of sndrcvinfo.sinfo_pr_value.
>> + *
>> + * 1) Create two sockets, the listening socket sets its RECVBUF small
>> + * 2) Create a connection. Send enough data to the non-reading listener
>> + * to fill the RCVBUF.
>> + * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
>> + * 6) Disable sinfo_pr_value on a message and send.
>> + * 7) Wait sinfo_pr_value time.
>> + * 8) Read out all the data at the receiver.
>> + * 9) Make sure timed out message did not make it.
>> + * 10) Make sure that the message with no timeout makes it to the receiver.
>> + *
>> + * Also test with SEND_FAILED notifications. Also, use a fragmented
>> + * message so as to also exercise the SEND_FAILED of fragmentation
>> + * code.
>> + */
>> +
>> +#include <stdio.h>
>> +#include <unistd.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <sys/types.h>
>> +#include <sys/socket.h>
>> +#include <sys/uio.h>
>> +#include <netinet/in.h>
>> +#include <sys/errno.h>
>> +#include <errno.h>
>> +#include <netinet/sctp.h>
>> +#include <sctputil.h>
>> +
>> +char *TCID = __FILE__;
>> +int TST_TOTAL = 6;
>> +int TST_CNT = 0;
>> +
>> +/* This is the size of our RCVBUF */
>> +#define SMALL_RCVBUF 3000
>> +
>> +/* MAX segment size */
>> +#define SMALL_MAXSEG 100
>> +
>> +/* RWND_SLOP is the extra data that fills up the rwnd */
>> +#define RWND_SLOP 100
>> +static char *fillmsg = NULL;
>> +static char *ttlmsg = "This should time out!\n";
>> +static char *nottlmsg = "This should NOT time out!\n";
>> +static char ttlfrag[SMALL_MAXSEG*3] = {0};
>> +static char *message = "Hello world\n";
>> +
>> +int main(int argc, char *argv[])
>> +{
>> + int sk1, sk2;
>> + sockaddr_storage_t loop1;
>> + sockaddr_storage_t loop2;
>> + struct iovec iov;
>> + struct msghdr inmessage;
>> + struct msghdr outmessage;
>> + char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
>> + char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
>> + struct cmsghdr *cmsg;
>> + struct sctp_sndrcvinfo *sinfo;
>> + struct iovec out_iov;
>> + int error;
>> + int pf_class, af_family;
>> + uint32_t ppid;
>> + uint32_t stream;
>> + sctp_assoc_t associd1, associd2;
>> + struct sctp_assoc_change *sac;
>> + struct sctp_event_subscribe subscribe;
>> + char *big_buffer;
>> + int offset;
>> + struct sctp_send_failed *ssf;
>> + int len; /* Really becomes 2xlen when set. */
>> + int orig_len;
>> + struct sctp_status gstatus;
>> +
>> + /* Rather than fflush() throughout the code, set stdout to
>> + * be unbuffered.
>> + */
>> + setvbuf(stdout, NULL, _IONBF, 0);
>> +
>> + /* Set some basic values which depend on the address family. */
>> +#if TEST_V6
>> + pf_class = PF_INET6;
>> + af_family = AF_INET6;
>> +
>> + loop1.v6.sin6_family = AF_INET6;
>> + loop1.v6.sin6_addr = in6addr_loopback;
>> + loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
>> +
>> + loop2.v6.sin6_family = AF_INET6;
>> + loop2.v6.sin6_addr = in6addr_loopback;
>> + loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
>> +#else
>> + pf_class = PF_INET;
>> + af_family = AF_INET;
>> +
>> + loop1.v4.sin_family = AF_INET;
>> + loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
>> + loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
>> +
>> + loop2.v4.sin_family = AF_INET;
>> + loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
>> + loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
>> +#endif /* TEST_V6 */
>> +
>> + /* Create the two endpoints which will talk to each other. */
>> + sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
>> + sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
>> +
>> + len = sizeof(int);
>> + error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
>> + &len);
>> + if (error)
>> + tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
>> + strerror(errno));
>> + /* Set the MAXSEG to something smallish. */
>> + {
>> + int val = SMALL_MAXSEG;
>> + test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
>> + }
>> +
>> + memset(&subscribe, 0, sizeof(subscribe));
>> + subscribe.sctp_data_io_event = 1;
>> + subscribe.sctp_association_event = 1;
>> + subscribe.sctp_send_failure_event = 1;
>> + test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
>> + test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
>> +
>> + /* Bind these sockets to the test ports. */
>> + test_bind(sk1, &loop1.sa, sizeof(loop1));
>> + test_bind(sk2, &loop2.sa, sizeof(loop2));
>> +
>> + /*
>> + * This code sets the associations RWND very small so we can
>> + * fill it. It does this by manipulating the rcvbuf as follows:
>> + * 1) Reduce the rcvbuf size on the socket
>> + * 2) create an association so that we advertize rcvbuf/2 as
>> + * our initial rwnd
>> + * 3) raise the rcvbuf value so that we don't drop data wile
>> + * receiving later data
>> + */
>> + len = SMALL_RCVBUF;
>> + error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len,
>> + sizeof(len));
>> + if (error)
>> + tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
>> + strerror(errno));
>> +
>> + /* Mark sk2 as being able to accept new associations. */
>> + test_listen(sk2, 1);
>> +
>> + /* Send the first message. This will create the association. */
>> + outmessage.msg_name = &loop2;
>> + outmessage.msg_namelen = sizeof(loop2);
>> + outmessage.msg_iov = &out_iov;
>> + outmessage.msg_iovlen = 1;
>> + outmessage.msg_control = outcmsg;
>> + outmessage.msg_controllen = sizeof(outcmsg);
>> + outmessage.msg_flags = 0;
>> + cmsg = CMSG_FIRSTHDR(&outmessage);
>> + cmsg->cmsg_level = IPPROTO_SCTP;
>> + cmsg->cmsg_type = SCTP_SNDRCV;
>> + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
>> + outmessage.msg_controllen = cmsg->cmsg_len;
>> + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>> + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
>> + ppid = rand(); /* Choose an arbitrary value. */
>> + stream = 1;
>> + sinfo->sinfo_ppid = ppid;
>> + sinfo->sinfo_stream = stream;
>> + outmessage.msg_iov->iov_base = message;
>> + outmessage.msg_iov->iov_len = strlen(message) + 1;
>> + test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
>> +
>> + /* Initialize inmessage for all receives. */
>> + big_buffer = test_malloc(REALLY_BIG);
>> + memset(&inmessage, 0, sizeof(inmessage));
>> + iov.iov_base = big_buffer;
>> + iov.iov_len = REALLY_BIG;
>> + inmessage.msg_iov = &iov;
>> + inmessage.msg_iovlen = 1;
>> + inmessage.msg_control = incmsg;
>> +
>> + /* Get the communication up message on sk2. */
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>> + test_check_msg_notification(&inmessage, error,
>> + sizeof(struct sctp_assoc_change),
>> + SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
>> + sac = (struct sctp_assoc_change *)iov.iov_base;
>> + associd2 = sac->sac_assoc_id;
>> +
>> + /* Get the communication up message on sk1. */
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
>> + test_check_msg_notification(&inmessage, error,
>> + sizeof(struct sctp_assoc_change),
>> + SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
>> + sac = (struct sctp_assoc_change *)iov.iov_base;
>> + associd1 = sac->sac_assoc_id;
>> +
>> + /* restore the rcvbuffer size for the receiving socket */
>> + error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
>> + sizeof(orig_len));
>> +
>> + if (error)
>> + tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
>> + strerror(errno));
>> +
>> + /* Get the first data message which was sent. */
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>> + test_check_msg_data(&inmessage, error, strlen(message) + 1,
>> + MSG_EOR, stream, ppid);
>> +
>> + /* Figure out how big to make our fillmsg */
>> + len = sizeof(struct sctp_status);
>> + memset(&gstatus,0,sizeof(struct sctp_status));
>> + gstatus.sstat_assoc_id = associd1;
>> + error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
>> +
>> + if (error)
>> + tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
>> + strerror(errno));
>> + tst_resm(TINFO, "Creating fillmsg of size %d",
>> + gstatus.sstat_rwnd+RWND_SLOP);
>> + fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
>> +
>> + /* Send a fillmsg */
>> + outmessage.msg_controllen = sizeof(outcmsg);
>> + outmessage.msg_flags = 0;
>> + cmsg = CMSG_FIRSTHDR(&outmessage);
>> + cmsg->cmsg_level = IPPROTO_SCTP;
>> + cmsg->cmsg_type = SCTP_SNDRCV;
>> + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
>> + outmessage.msg_controllen = cmsg->cmsg_len;
>> + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>> + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
>> + ppid++;
>> + stream++;
>> + sinfo->sinfo_ppid = ppid;
>> + sinfo->sinfo_stream = stream;
>> + memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
>> + fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
>> + outmessage.msg_iov->iov_base = fillmsg;
>> + outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP;
>> + outmessage.msg_name = NULL;
>> + outmessage.msg_namelen = 0;
>> + sinfo->sinfo_assoc_id = associd1;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>> + sinfo->sinfo_pr_value = 0;
>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
>> + gstatus.sstat_rwnd+RWND_SLOP);
>> +
>> + /* Now send the message with timeout. */
>> + sinfo->sinfo_ppid = ppid;
>> + sinfo->sinfo_stream = stream;
>> + outmessage.msg_iov->iov_base = ttlmsg;
>> + outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1;
>> + outmessage.msg_name = NULL;
>> + outmessage.msg_namelen = 0;
>> + sinfo->sinfo_assoc_id = associd1;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
>> + sinfo->sinfo_pr_value = 2;
>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
>> +
>> + tst_resm(TPASS, "Send a message with timeout");
>> +
>> + /* Next send a message with no timeout. */
>> + sinfo->sinfo_ppid = ppid;
>> + sinfo->sinfo_stream = stream;
>> + outmessage.msg_iov->iov_base = nottlmsg;
>> + outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1;
>> + outmessage.msg_name = NULL;
>> + outmessage.msg_namelen = 0;
>> + sinfo->sinfo_assoc_id = associd1;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>> + sinfo->sinfo_pr_value = 0;
>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
>> +
>> + tst_resm(TPASS, "Send a message with no timeout");
>> +
>> + /* And finally a fragmented message that will time out. */
>> + sinfo->sinfo_ppid = ppid;
>> + sinfo->sinfo_stream = stream;
>> + memset(ttlfrag, '0', sizeof(ttlfrag));
>> + ttlfrag[sizeof(ttlfrag)-1] = '\0';
>> + outmessage.msg_iov->iov_base = ttlfrag;
>> + outmessage.msg_iov->iov_len = sizeof(ttlfrag);
>> + outmessage.msg_name = NULL;
>> + outmessage.msg_namelen = 0;
>> + sinfo->sinfo_assoc_id = associd1;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
>> + sinfo->sinfo_pr_value = 2;
>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
>> +
>> + tst_resm(TPASS, "Send a fragmented message with timeout");
>> +
>> + /* Sleep waiting for the message to time out. */
>> + tst_resm(TINFO, " ** SLEEPING for 3 seconds **");
>> + sleep(3);
>> +
>> + /* Read the fillmsg snuck in between the ttl'd messages. */
>> + do {
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>> + } while (!(inmessage.msg_flags & MSG_EOR));
>> +
>> + /* Now get the message that did NOT time out. */
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>> + test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1,
>> + MSG_EOR, stream, ppid);
>> + if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1))
>> + tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!");
>> +
>> + tst_resm(TPASS, "Receive message with no timeout");
>> +
>> + /* Get the SEND_FAILED notification for the message that DID
>> + * time out.
>> + */
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
>> + test_check_msg_notification(&inmessage, error,
>> + sizeof(struct sctp_send_failed) +
>> + strlen(ttlmsg) + 1,
>> + SCTP_SEND_FAILED, 0);
>> + ssf = (struct sctp_send_failed *)iov.iov_base;
>> + if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
>> + tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
>> +
>> + tst_resm(TPASS, "Receive SEND_FAILED for message with timeout");
>> +
>> + /* Get the SEND_FAILED notification for the fragmented message that
>> + * DID time out.
>> + */
>> + offset = 0;
>> + do {
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
>> + test_check_msg_notification(&inmessage, error,
>> + sizeof(struct sctp_send_failed) +
>> + SMALL_MAXSEG,
>> + SCTP_SEND_FAILED, 0);
>> + ssf = (struct sctp_send_failed *)iov.iov_base;
>> + if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
>> + SMALL_MAXSEG))
>> + tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
>> + offset += SMALL_MAXSEG;
>> + } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */
>> +
>> + tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with "
>> + "timeout");
>> +
>> + /* Shut down the link. */
>> + close(sk1);
>> +
>> + /* Get the shutdown complete notification. */
>> + inmessage.msg_controllen = sizeof(incmsg);
>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>> + test_check_msg_notification(&inmessage, error,
>> + sizeof(struct sctp_assoc_change),
>> + SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
>> +
>> + close(sk2);
>> +
>> + /* Indicate successful completion. */
>> + return 0;
>> +}
>> diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
>> index c275e45..aaa56e9 100644
>> --- a/src/func_tests/test_sctp_sendrecvmsg.c
>> +++ b/src/func_tests/test_sctp_sendrecvmsg.c
>> @@ -243,7 +243,7 @@ int main(int argc, char *argv[])
>> /* Now send a message that will timeout. */
>> test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
>> (struct sockaddr *)&loop2, sizeof(loop2),
>> - ppid, 0, stream, 2000, 0);
>> + ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
>>
>> tst_resm(TPASS, "sctp_sendmsg with ttl");
>>
>> @@ -259,7 +259,7 @@ int main(int argc, char *argv[])
>> ttlfrag[sizeof(ttlfrag)-1] = '\0';
>> test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
>> (struct sockaddr *)&loop2, sizeof(loop2),
>> - ppid, 0, stream, 2000, 0);
>> + ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
>>
>> tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
>>
>> @@ -335,7 +335,8 @@ int main(int argc, char *argv[])
>> snd_sinfo.sinfo_ppid = rand();
>> snd_sinfo.sinfo_flags = 0;
>> snd_sinfo.sinfo_stream = 2;
>> - snd_sinfo.sinfo_timetolive = 0;
>> + snd_sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>> + snd_sinfo.sinfo_pr_value = 0;
>> snd_sinfo.sinfo_assoc_id = associd1;
>> test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
>> MSG_NOSIGNAL);
>> diff --git a/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
>> index d9bdf1b..dc66722 100644
>> --- a/src/func_tests/test_timetolive.c
>> +++ b/src/func_tests/test_timetolive.c
>> @@ -39,14 +39,14 @@
>>
>> /*
>> * This is a basic functional test for the SCTP kernel
>> - * implementation of sndrcvinfo.sinfo_timetolive.
>> + * implementation of sndrcvinfo.sinfo_pr_value.
>> *
>> * 1) Create two sockets, the listening socket sets its RECVBUF small
>> * 2) Create a connection. Send enough data to the non-reading listener
>> * to fill the RCVBUF.
>> - * 5) Set sinfo_timetolive on a message and send.
>> - * 6) Disable sinfo_timetolive on a message and send.
>> - * 7) Wait sinfo_timetolive.
>> + * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
>> + * 6) Disable sinfo_pr_value on a message and send.
>> + * 7) Wait sinfo_pr_value time.
>> * 8) Read out all the data at the receiver.
>> * 9) Make sure timed out message did not make it.
>> * 10) Make sure that the message with no timeout makes it to the receiver.
>> @@ -288,7 +288,8 @@ int main(int argc, char *argv[])
>> outmessage.msg_name = NULL;
>> outmessage.msg_namelen = 0;
>> sinfo->sinfo_assoc_id = associd1;
>> - sinfo->sinfo_timetolive = 0;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>> + sinfo->sinfo_pr_value = 0;
>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
>> gstatus.sstat_rwnd+RWND_SLOP);
>>
>> @@ -300,7 +301,8 @@ int main(int argc, char *argv[])
>> outmessage.msg_name = NULL;
>> outmessage.msg_namelen = 0;
>> sinfo->sinfo_assoc_id = associd1;
>> - sinfo->sinfo_timetolive = 2000;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
>> + sinfo->sinfo_pr_value = 2000;
>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
>>
>> tst_resm(TPASS, "Send a message with timeout");
>> @@ -313,7 +315,8 @@ int main(int argc, char *argv[])
>> outmessage.msg_name = NULL;
>> outmessage.msg_namelen = 0;
>> sinfo->sinfo_assoc_id = associd1;
>> - sinfo->sinfo_timetolive = 0;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>> + sinfo->sinfo_pr_value = 0;
>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
>>
>> tst_resm(TPASS, "Send a message with no timeout");
>> @@ -328,7 +331,8 @@ int main(int argc, char *argv[])
>> outmessage.msg_name = NULL;
>> outmessage.msg_namelen = 0;
>> sinfo->sinfo_assoc_id = associd1;
>> - sinfo->sinfo_timetolive = 2000;
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
>> + sinfo->sinfo_pr_value = 2000;
>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
>>
>> tst_resm(TPASS, "Send a fragmented message with timeout");
>> diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h
>> index ae557a5..5a6cea2 100644
>> --- a/src/include/netinet/sctp.h
>> +++ b/src/include/netinet/sctp.h
>> @@ -184,9 +184,10 @@ struct sctp_sndrcvinfo {
>> __u16 sinfo_stream;
>> __u16 sinfo_ssn;
>> __u16 sinfo_flags;
>> + __u16 sinfo_pr_policy;
>> __u32 sinfo_ppid;
>> __u32 sinfo_context;
>> - __u32 sinfo_timetolive;
>> + __u32 sinfo_pr_value;
>> __u32 sinfo_tsn;
>> __u32 sinfo_cumtsn;
>> sctp_assoc_t sinfo_assoc_id;
>> @@ -200,12 +201,25 @@ struct sctp_sndrcvinfo {
>> */
>>
>> enum sctp_sinfo_flags {
>> - SCTP_UNORDERED = 1, /* Send/receive message unordered. */
>> - SCTP_ADDR_OVER = 2, /* Override the primary destination. */
>> - SCTP_ABORT=4, /* Send an ABORT message to the peer. */
>> - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
>> + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
>> + SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
>> + SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
>> + SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
>> };
>>
>> +/*
>> + * sinfo_pr_policy: 16 bits (unsigned integer)
>> + *
>> + * This field may contain the partial reliability used to
>> + * send the message.
>> + */
>> +
>> +enum sctp_sinfo_pr_policy {
>> + SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
>> + SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliable */
>> + SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliable */
>> + SCTP_PR_SCTP_RTX = 0x0003, /* Retransmist partial reliable */
>> +};
>>
>> typedef union {
>> __u8 raw;
>> @@ -816,7 +830,7 @@ int sctp_freeladdrs(struct sockaddr *addrs);
>> */
>> int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
>> socklen_t tolen, uint32_t ppid, uint32_t flags,
>> - uint16_t stream_no, uint32_t timetolive, uint32_t context);
>> + uint16_t stream_no, uint32_t pr_value, uint32_t context);
>>
>> /* This library function assist the user with sending a message without
>> * dealing directly with the CMSG header.
>> diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
>> index 1de592d..a674646 100644
>> --- a/src/lib/sendmsg.c
>> +++ b/src/lib/sendmsg.c
>> @@ -31,7 +31,7 @@
>> int
>> sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
>> socklen_t tolen, uint32_t ppid, uint32_t flags,
>> - uint16_t stream_no, uint32_t timetolive, uint32_t context)
>> + uint16_t stream_no, uint32_t pr_value, uint32_t context)
>> {
>> struct msghdr outmsg;
>> struct iovec iov;
>> @@ -61,9 +61,22 @@ sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
>> sinfo->sinfo_ppid = ppid;
>> sinfo->sinfo_flags = flags;
>> sinfo->sinfo_stream = stream_no;
>> - sinfo->sinfo_timetolive = timetolive;
>> sinfo->sinfo_context = context;
>>
>> + sinfo->sinfo_pr_policy = sinfo->sinfo_flags & 0xff;
>> + sinfo->sinfo_pr_value = pr_value;
>> +
>> + printf("sinfo_flags: %x sinfo_pr_policy: %d sinfo_pr_value: %d\n",
>> + sinfo->sinfo_flags, sinfo->sinfo_pr_policy, sinfo->sinfo_pr_value);
>> +
>> + /* If we get an invalid sinfo_pr_policy force it to
>> + * SCTP_PR_SCTP_NONE or shall we better fail and set a
>> + * EINVAL error??
>> + */
>> +
>> + if(sinfo->sinfo_pr_policy > SCTP_PR_SCTP_RTX)
>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>> +
>> return sendmsg(s, &outmsg, 0);
>> }
>>
>> diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
>> index 347c91b..0afbc36 100644
>> --- a/src/testlib/sctputil.h
>> +++ b/src/testlib/sctputil.h
>> @@ -270,11 +270,11 @@ static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
>> static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
>> struct sockaddr *to, socklen_t tolen,
>> uint32_t ppid, uint32_t flags,
>> - uint16_t stream_no, uint32_t timetolive,
>> + uint16_t stream_no, uint32_t pr_value,
>> uint32_t context)
>> {
>> int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
>> - timetolive, context);
>> + pr_value, context);
>> if (len != error)
>> tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
>> error, errno);
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] Replace timetolive with pr_policy and pr_value
2008-12-03 1:59 [PATCH] Replace timetolive with pr_policy and pr_value Horacio Sanson
` (3 preceding siblings ...)
2008-12-16 7:53 ` Horacio Sanson
@ 2008-12-16 14:33 ` Vlad Yasevich
4 siblings, 0 replies; 6+ messages in thread
From: Vlad Yasevich @ 2008-12-16 14:33 UTC (permalink / raw)
To: linux-sctp
Horacio Sanson wrote:
> On Tue, Dec 16, 2008 at 12:55 AM, Vlad Yasevich
> <vladislav.yasevich@hp.com> wrote:
>>> I created a new patch set that fixes the SCTP_PR_SCTP_RTX partial
>>> reliability that was not working and added a test program to test it.
>>> Again all v4tests and v6tests pass including my own tests.
>>>
>>> This includes the previous patches so the previous ones should be
>>> ignored. But no one seems to be looking at my patches so I think there
>>> should be no problems anyway :( .
>>>
>>>
>> I am looking, I am just busy with other things as well. Please be patient.
>>
>
> Thanks, I really appreciate the feedback.
>
>> As a first step that will make review much easier, please get rid of the whitespace
>> changes that show up. That will improve the readability of the patches.
>>
>
> I tried my best here but seems I did it all wrong. I though that using
> a command like "git apply --check --whitespaces=error-all" was enough
> to make sure no trailing spaces or spaces before tabs were present.
> Seems this is not the case as the command gives no errors even though
> there are in fact white spaces all over the place. Will check again.
Look at the git-diff generated patch and look for lines like this:
> - union sctp_addr_param *);
> + union sctp_addr_param *);
Note, they have the same text but they show up in diff. This means that there
is a difference in the whitespace used in those lines. --whitespace doesn't
catch everything. Vim and emacs diff options typically show where the change
occurred. You can save the new file, then do git-checkout <filename> and bring
up both in one of the graphic diff tools to see where the change was.
>
>> Also, please separate the patches into separate e-mails. Look at git-send-email
>> and git-format-patch for more information.
>>
>
> Will rewrite my patches again trying to split the changes in smaller
> and more concise steps.
I thing you patches were already split, however, they were in one email. It's
easier to review when each patch is by itself.
>
>> Thanks
>> -vlad
>>
>>>
>>>
>>> diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
>>> index 9661d7b..ffda4c5 100644
>>> --- a/include/net/sctp/structs.h
>>> +++ b/include/net/sctp/structs.h
>>> @@ -208,7 +208,7 @@ extern struct sctp_globals {
>>>
>>> /* Lock that protects the local_addr_list writers */
>>> spinlock_t addr_list_lock;
>>> -
>>> +
>>> /* Flag to indicate if addip is enabled. */
>>> int addip_enable;
>>> int addip_noauth_enable;
>>> @@ -282,7 +282,8 @@ struct sctp_sock {
>>> __u32 default_ppid;
>>> __u16 default_flags;
>>> __u32 default_context;
>>> - __u32 default_timetolive;
>>> + __u16 default_pr_policy;
>>> + __u32 default_pr_value;
>> Please don't add any memory holes when adding new entries to the structure.
>
> Could you please elaborate in this comment?? Has this something to do
> with memory alignment issues of some sort? How can I avoid this memory
> hole you mention??
sctp_sock is already huge and adding memory holes just makes it even bigger.
when possible, try to find a hole to fill. If not possible, try to create
a smallest hole possible. Use pahole to see the alignment and memory holes
(git://git.kernel.org/pub/scm/linux/kernel/git/acme/pahole.git)
For the above bit, there is already a 16 bit memory hole between default_flags
and default-context. If the default_* elements fall into the same cache line,
then it's better to fill that 16 bit memory hole with pr_policy element. It
doesn't matter that the elements are not together. By being in the same cache
line you get free access to all of them.
-vlad
>
> thanks,
> Horacio
>
>
>>> __u32 default_rcv_context;
>>> int max_burst;
>>>
>>> @@ -390,7 +391,7 @@ struct sctp_cookie {
>>> /* This holds the originating address of the INIT packet. */
>>> union sctp_addr peer_addr;
>>>
>>> - /* IG Section 2.35.3
>>> + /* IG Section 2.35.3
>>> * Include the source port of the INIT-ACK
>>> */
>>> __u16 my_port;
>>> @@ -398,7 +399,7 @@ struct sctp_cookie {
>>> __u8 prsctp_capable;
>>>
>>> /* Padding for future use */
>>> - __u8 padding;
>>> + __u8 padding;
>> White space? Please limit the scope of your patches.
>>
>>> __u32 adaptation_ind;
>>>
>>> @@ -512,12 +513,12 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
>>> }
>>>
>>> /* Skip over this ssn and all below. */
>>> -static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
>>> +static inline void sctp_ssn_skip(struct sctp_stream *stream, __u16 id,
>>> __u16 ssn)
>>> {
>>> stream->ssn[id] = ssn+1;
>>> }
>>> -
>>> +
>> More whitespace?
>>
>>> /*
>>> * Pointers to address related SCTP functions.
>>> * (i.e. things that depend on the address family.)
>>> @@ -575,7 +576,7 @@ struct sctp_af {
>>> union sctp_addr_param *,
>>> __be16 port, int iif);
>>> int (*to_addr_param) (const union sctp_addr *,
>>> - union sctp_addr_param *);
>>> + union sctp_addr_param *);
>> Again?
>>
>>> int (*addr_valid) (union sctp_addr *,
>>> struct sctp_sock *,
>>> const struct sk_buff *);
>>> @@ -626,13 +627,15 @@ struct sctp_datamsg {
>>> struct list_head track;
>>> /* Reference counting. */
>>> atomic_t refcnt;
>>> +
>>> + /* Policy used to determine expired messages */
>>> + unsigned long expires_policy;
>>> /* When is this message no longer interesting to the peer? */
>>> unsigned long expires_at;
>>> /* Did the messenge fail to send? */
>>> int send_error;
>>> char send_failed;
>>> /* Control whether chunks from this message can be abandoned. */
>>> - char can_abandon;
>>> };
>>>
>>> struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
>>> @@ -1339,7 +1342,7 @@ struct sctp_endpoint {
>>> * on every receive.
>>> */
>>> __u8 *digest;
>>> -
>>> +
>> Again? I am done at this point!!!
>>
>>> /* sendbuf acct. policy. */
>>> __u32 sndbuf_policy;
>>>
>>> @@ -1759,9 +1762,10 @@ struct sctp_association {
>>> /* Default send parameters. */
>>> __u16 default_stream;
>>> __u16 default_flags;
>>> + __u16 default_pr_policy;
>>> __u32 default_ppid;
>>> __u32 default_context;
>>> - __u32 default_timetolive;
>>> + __u32 default_pr_value;
>>>
>>> /* Default receive parameters */
>>> __u32 default_rcv_context;
>>> diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h
>>> index f205b10..74c0aba 100644
>>> --- a/include/net/sctp/user.h
>>> +++ b/include/net/sctp/user.h
>>> @@ -71,7 +71,7 @@ enum sctp_optname {
>>> #define SCTP_NODELAY SCTP_NODELAY
>>> SCTP_AUTOCLOSE,
>>> #define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
>>> - SCTP_SET_PEER_PRIMARY_ADDR,
>>> + SCTP_SET_PEER_PRIMARY_ADDR,
>>> #define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
>>> SCTP_PRIMARY_ADDR,
>>> #define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
>>> @@ -120,7 +120,7 @@ enum sctp_optname {
>>> #define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS
>>>
>>>
>>> - /* Internal Socket Options. Some of the sctp library functions are
>>> + /* Internal Socket Options. Some of the sctp library functions are
>>> * implemented using these socket options.
>>> */
>>> SCTP_SOCKOPT_BINDX_ADD = 100,/* BINDX requests for adding addresses. */
>>> @@ -183,9 +183,10 @@ struct sctp_sndrcvinfo {
>>> __u16 sinfo_stream;
>>> __u16 sinfo_ssn;
>>> __u16 sinfo_flags;
>>> + __u16 sinfo_pr_policy;
>>> __u32 sinfo_ppid;
>>> __u32 sinfo_context;
>>> - __u32 sinfo_timetolive;
>>> + __u32 sinfo_pr_value;
>>> __u32 sinfo_tsn;
>>> __u32 sinfo_cumtsn;
>>> sctp_assoc_t sinfo_assoc_id;
>>> @@ -199,12 +200,25 @@ struct sctp_sndrcvinfo {
>>> */
>>>
>>> enum sctp_sinfo_flags {
>>> - SCTP_UNORDERED = 1, /* Send/receive message unordered. */
>>> - SCTP_ADDR_OVER = 2, /* Override the primary destination. */
>>> - SCTP_ABORT=4, /* Send an ABORT message to the peer. */
>>> - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
>>> + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. (0x0200) */
>>> + SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
>>> + SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
>>> + SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
>>> };
>>>
>>> +/*
>>> + * sinfo_pr_policy: 16 bits (unsigned integer)
>>> + *
>>> + * This field may contain the partial reliability used to
>>> + * send the message.
>>> + */
>>> +
>>> +enum sctp_sinfo_pr_policy {
>>> + SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
>>> + SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliability */
>>> + SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliability (EXPERIMENTAL) */
>>> + SCTP_PR_SCTP_RTX = 0x0003, /* Retransmis partial reliability (EXPERIMENTAL) */
>>> +};
>>>
>>> typedef union {
>>> __u8 raw;
>>> @@ -479,7 +493,7 @@ typedef enum sctp_sn_error {
>>> *
>>> * The protocol parameters used to initialize and bound retransmission
>>> * timeout (RTO) are tunable. See [SCTP] for more information on how
>>> - * these parameters are used in RTO calculation.
>>> + * these parameters are used in RTO calculation.
>>> */
>>> struct sctp_rtoinfo {
>>> sctp_assoc_t srto_assoc_id;
>>> @@ -717,9 +731,9 @@ struct sctp_authchunks {
>>>
>>> /*
>>> * 8.3, 8.5 get all peer/local addresses in an association.
>>> - * This parameter struct is used by SCTP_GET_PEER_ADDRS and
>>> + * This parameter struct is used by SCTP_GET_PEER_ADDRS and
>>> * SCTP_GET_LOCAL_ADDRS socket options used internally to implement
>>> - * sctp_getpaddrs() and sctp_getladdrs() API.
>>> + * sctp_getpaddrs() and sctp_getladdrs() API.
>>> */
>>> struct sctp_getaddrs_old {
>>> sctp_assoc_t assoc_id;
>>>
>>>
>>>
>>> diff --git a/net/sctp/associola.c b/net/sctp/associola.c
>>> index f4b2304..c178139 100644
>>> --- a/net/sctp/associola.c
>>> +++ b/net/sctp/associola.c
>>> @@ -302,7 +302,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
>>> asoc->default_ppid = sp->default_ppid;
>>> asoc->default_flags = sp->default_flags;
>>> asoc->default_context = sp->default_context;
>>> - asoc->default_timetolive = sp->default_timetolive;
>>> + asoc->default_pr_policy = sp->default_pr_policy;
>>> + asoc->default_pr_value = sp->default_pr_value;
>>> asoc->default_rcv_context = sp->default_rcv_context;
>>>
>>> /* AUTH related initializations */
>>> diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
>>> index 1748ef9..4cdfe49 100644
>>> --- a/net/sctp/chunk.c
>>> +++ b/net/sctp/chunk.c
>>> @@ -56,7 +56,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
>>> atomic_set(&msg->refcnt, 1);
>>> msg->send_failed = 0;
>>> msg->send_error = 0;
>>> - msg->can_abandon = 0;
>>> + msg->expires_policy = SCTP_PR_SCTP_NONE;
>>> msg->expires_at = 0;
>>> INIT_LIST_HEAD(&msg->chunks);
>>> }
>>> @@ -170,13 +170,26 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
>>> /* Note: Calculate this outside of the loop, so that all fragments
>>> * have the same expiration.
>>> */
>>> - if (sinfo->sinfo_timetolive) {
>>> - /* sinfo_timetolive is in milliseconds */
>>> - msg->expires_at = jiffies +
>>> - msecs_to_jiffies(sinfo->sinfo_timetolive);
>>> - msg->can_abandon = 1;
>>> - SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
>>> - __func__, msg, msg->expires_at, jiffies);
>>> +
>>> + msg->expires_policy = sinfo->sinfo_pr_policy;
>>> +
>>> + if(msg->expires_policy) {
>>> + switch(msg->expires_policy) {
>>> + case SCTP_PR_SCTP_TTL:
>>> + /* sinfo_timetolive is in milliseconds */
>>> + msg->expires_at = jiffies +
>>> + msecs_to_jiffies(sinfo->sinfo_pr_value);
>>> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
>>> + __func__, msg, msg->expires_at, jiffies);
>>> + break;
>>> + case SCTP_PR_SCTP_BUF:
>>> + break;
>>> + case SCTP_PR_SCTP_RTX:
>>> + msg->expires_at = sinfo->sinfo_pr_value;
>>> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_after: %ld retransmissions \n",
>>> + __func__, msg, msg->expires_at);
>>> + break;
>>> + }
>>> }
>>>
>>> max = asoc->frag_point;
>>> @@ -291,11 +304,23 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
>>> {
>>> struct sctp_datamsg *msg = chunk->msg;
>>>
>>> - if (!msg->can_abandon)
>>> + if (!msg->expires_policy)
>>> return 0;
>>>
>>> - if (time_after(jiffies, msg->expires_at))
>>> - return 1;
>>> + switch(msg->expires_policy) {
>>> + case SCTP_PR_SCTP_TTL:
>>> + if (time_after(jiffies, msg->expires_at))
>>> + return 1;
>>> + case SCTP_PR_SCTP_BUF:
>>> + /* TODO: Implement this */
>>> + return 0;
>>> + case SCTP_PR_SCTP_RTX:
>>> + if(--msg->expires_at <= 0) {
>>> + SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld EXPIRED!!\n",
>>> + __func__, msg, msg->expires_at);
>>> + return 1;
>>> + }
>>> + }
>>>
>>> return 0;
>>> }
>>> diff --git a/net/sctp/output.c b/net/sctp/output.c
>>> index c3f417f..b344a9d 100644
>>> --- a/net/sctp/output.c
>>> +++ b/net/sctp/output.c
>>> @@ -745,7 +745,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
>>> asoc->peer.rwnd = rwnd;
>>> /* Has been accepted for transmission. */
>>> if (!asoc->peer.prsctp_capable)
>>> - chunk->msg->can_abandon = 0;
>>> + chunk->msg->expires_policy = SCTP_PR_SCTP_NONE;
>>>
>>> finish:
>>> return retval;
>>> diff --git a/net/sctp/socket.c b/net/sctp/socket.c
>>> index a1b9045..0dfc137 100644
>>> --- a/net/sctp/socket.c
>>> +++ b/net/sctp/socket.c
>>> @@ -1698,7 +1698,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
>>> default_sinfo.sinfo_flags = asoc->default_flags;
>>> default_sinfo.sinfo_ppid = asoc->default_ppid;
>>> default_sinfo.sinfo_context = asoc->default_context;
>>> - default_sinfo.sinfo_timetolive = asoc->default_timetolive;
>>> + default_sinfo.sinfo_pr_policy = asoc->default_pr_policy;
>>> + default_sinfo.sinfo_pr_value = asoc->default_pr_value;
>>> default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
>>> sinfo = &default_sinfo;
>>> }
>>> @@ -2539,7 +2540,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt
>>> * in to this call the sctp_sndrcvinfo structure defined in Section
>>> * 5.2.2) The input parameters accepted by this call include
>>> * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
>>> - * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
>>> + * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
>>> * to this call if the caller is using the UDP model.
>>> */
>>> static int sctp_setsockopt_default_send_param(struct sock *sk,
>>> @@ -2563,13 +2564,15 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
>>> asoc->default_flags = info.sinfo_flags;
>>> asoc->default_ppid = info.sinfo_ppid;
>>> asoc->default_context = info.sinfo_context;
>>> - asoc->default_timetolive = info.sinfo_timetolive;
>>> + asoc->default_pr_policy = info.sinfo_pr_policy;
>>> + asoc->default_pr_value = info.sinfo_pr_value;
>>> } else {
>>> sp->default_stream = info.sinfo_stream;
>>> sp->default_flags = info.sinfo_flags;
>>> sp->default_ppid = info.sinfo_ppid;
>>> sp->default_context = info.sinfo_context;
>>> - sp->default_timetolive = info.sinfo_timetolive;
>>> + sp->default_pr_policy = info.sinfo_pr_policy;
>>> + sp->default_pr_value = info.sinfo_pr_value;
>>> }
>>>
>>> return 0;
>>> @@ -3524,7 +3527,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
>>> sp->default_ppid = 0;
>>> sp->default_flags = 0;
>>> sp->default_context = 0;
>>> - sp->default_timetolive = 0;
>>> + sp->default_pr_policy = 0;
>>> + sp->default_pr_value = 0;
>>>
>>> sp->default_rcv_context = 0;
>>> sp->max_burst = sctp_max_burst;
>>> @@ -4824,7 +4828,7 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
>>> * in to this call the sctp_sndrcvinfo structure defined in Section
>>> * 5.2.2) The input parameters accepted by this call include
>>> * sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
>>> - * sinfo_timetolive. The user must provide the sinfo_assoc_id field in
>>> + * sinfo_pr_policy. The user must provide the sinfo_assoc_id field in
>>> * to this call if the caller is using the UDP model.
>>> *
>>> * For getsockopt, it get the default sctp_sndrcvinfo structure.
>>> @@ -4854,13 +4858,15 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
>>> info.sinfo_flags = asoc->default_flags;
>>> info.sinfo_ppid = asoc->default_ppid;
>>> info.sinfo_context = asoc->default_context;
>>> - info.sinfo_timetolive = asoc->default_timetolive;
>>> + info.sinfo_pr_policy = asoc->default_pr_policy;
>>> + info.sinfo_pr_value = asoc->default_pr_value;
>>> } else {
>>> info.sinfo_stream = sp->default_stream;
>>> info.sinfo_flags = sp->default_flags;
>>> info.sinfo_ppid = sp->default_ppid;
>>> info.sinfo_context = sp->default_context;
>>> - info.sinfo_timetolive = sp->default_timetolive;
>>> + info.sinfo_pr_policy = sp->default_pr_policy;
>>> + info.sinfo_pr_value = sp->default_pr_value;
>>> }
>>>
>>> if (put_user(len, optlen))
>>> @@ -6107,10 +6113,17 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
>>> (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>>>
>>> /* Minimally, validate the sinfo_flags. */
>>> +
>>> + /* TODO this validation does not work with the new
>>> + * SCTP_PR_SCTP_XXX flags
>>> + */
>>> +
>>> + /*
>>> if (cmsgs->info->sinfo_flags &
>>> ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
>>> SCTP_ABORT | SCTP_EOF))
>>> return -EINVAL;
>>> + */
>>> break;
>>>
>>> default:
>>> diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
>>> index 5f186ca..2c6f111 100644
>>> --- a/net/sctp/ulpevent.c
>>> +++ b/net/sctp/ulpevent.c
>>> @@ -948,7 +948,8 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
>>> sinfo.sinfo_context = event->asoc->default_rcv_context;
>>>
>>> /* These fields are not used while receiving. */
>>> - sinfo.sinfo_timetolive = 0;
>>> + sinfo.sinfo_pr_policy = 0;
>>> + sinfo.sinfo_pr_value = 0;
>>>
>>> put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV,
>>> sizeof(struct sctp_sndrcvinfo), (void *)&sinfo);
>>>
>>>
>>>
>>> diff --git a/src/func_tests/Makefile.am b/src/func_tests/Makefile.am
>>> index b985685..a7167d5 100644
>>> --- a/src/func_tests/Makefile.am
>>> +++ b/src/func_tests/Makefile.am
>>> @@ -5,7 +5,7 @@ include $(top_srcdir)/Makefile.rules
>>> include $(top_srcdir)/Makefile.dirs
>>>
>>> # General compilation flags
>>> -INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
>>> +INCLUDES = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib
>>> AM_CFLAGS = -g -Wall -Wstrict-prototypes -Wimplicit-function-declaration
>>> AM_LDFLAGS = -lpthread
>>> LDADD = $(top_builddir)/src/lib/libsctp.la \
>>> @@ -27,6 +27,7 @@ PASSING_KERN_TESTS = \
>>> test_connectx \
>>> test_recvmsg \
>>> test_timetolive \
>>> + test_rtxtolive \
>>> test_sctp_sendrecvmsg \
>>> test_getname \
>>> test_tcp_style\
>>> @@ -55,6 +56,7 @@ PASSING_V6_KERN_TESTS = \
>>> test_inaddr_any_v6 \
>>> test_peeloff_v6 \
>>> test_timetolive_v6 \
>>> + test_rtxtolive_v6 \
>>> test_sctp_sendrecvmsg_v6 \
>>> test_getname_v6 \
>>> test_tcp_style_v6
>>> @@ -102,21 +104,22 @@ v6test: ${PASSING_V6_KERN_TESTS}
>>> @echo "Hoody hoo!"
>>>
>>> # Specifying the sources
>>> -test_assoc_abort_SOURCES = test_assoc_abort.c
>>> -test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
>>> -test_autoclose_SOURCES = test_autoclose.c
>>> -test_basic_SOURCES = test_basic.c
>>> -test_fragments_SOURCES = test_fragments.c
>>> -test_inaddr_any_SOURCES = test_inaddr_any.c
>>> -test_peeloff_SOURCES = test_peeloff.c
>>> -test_sockopt_SOURCES = test_sockopt.c
>>> -test_connect_SOURCES = test_connect.c
>>> -test_connectx_SOURCES = test_connectx.c
>>> -test_recvmsg_SOURCES = test_recvmsg.c
>>> +test_assoc_abort_SOURCES = test_assoc_abort.c
>>> +test_assoc_shutdown_SOURCES = test_assoc_shutdown.c
>>> +test_autoclose_SOURCES = test_autoclose.c
>>> +test_basic_SOURCES = test_basic.c
>>> +test_fragments_SOURCES = test_fragments.c
>>> +test_inaddr_any_SOURCES = test_inaddr_any.c
>>> +test_peeloff_SOURCES = test_peeloff.c
>>> +test_sockopt_SOURCES = test_sockopt.c
>>> +test_connect_SOURCES = test_connect.c
>>> +test_connectx_SOURCES = test_connectx.c
>>> +test_recvmsg_SOURCES = test_recvmsg.c
>>> test_timetolive_SOURCES = test_timetolive.c
>>> +test_rtxtolive_SOURCES = test_rtxtolive.c
>>> test_sctp_sendrecvmsg_SOURCES = test_sctp_sendrecvmsg.c
>>> -test_getname_SOURCES = test_getname.c
>>> -test_tcp_style_SOURCES = test_tcp_style.c
>>> +test_getname_SOURCES = test_getname.c
>>> +test_tcp_style_SOURCES = test_tcp_style.c
>>>
>>> test_1_to_1_socket_bind_listen_SOURCES = test_1_to_1_socket_bind_listen.c
>>> test_1_to_1_accept_close_SOURCES = test_1_to_1_accept_close.c
>>> @@ -157,6 +160,9 @@ test_peeloff_v6_CFLAGS = ${V6FLAGS}
>>> test_timetolive_v6_SOURCES = test_timetolive.c
>>> test_timetolive_v6_CFLAGS = ${V6FLAGS}
>>>
>>> +test_rtxtolive_v6_SOURCES = test_rtxtolive.c
>>> +test_rtxtolive_v6_CFLAGS = ${V6FLAGS}
>>> +
>>> test_sctp_sendrecvmsg_v6_SOURCES = test_sctp_sendrecvmsg.c
>>> test_sctp_sendrecvmsg_v6_CFLAGS = ${V6FLAGS}
>>>
>>> diff --git a/src/func_tests/test_rtxtolive.c b/src/func_tests/test_rtxtolive.c
>>> new file mode 100644
>>> index 0000000..9aa03ad
>>> --- /dev/null
>>> +++ b/src/func_tests/test_rtxtolive.c
>>> @@ -0,0 +1,410 @@
>>> +/* SCTP kernel Implementation
>>> + * (C) Copyright IBM Corp. 2001, 2003
>>> + * Copyright (c) 1999-2000 Cisco, Inc.
>>> + * Copyright (c) 1999-2001 Motorola, Inc.
>>> + * Copyright (c) 2001 Intel Corp.
>>> + * Copyright (c) 2001 Nokia, Inc.
>>> + *
>>> + * The SCTP implementation is free software;
>>> + * you can redistribute it and/or modify it under the terms of
>>> + * the GNU General Public License as published by
>>> + * the Free Software Foundation; either version 2, or (at your option)
>>> + * any later version.
>>> + *
>>> + * The SCTP implementation is distributed in the hope that it
>>> + * will be useful, but WITHOUT ANY WARRANTY; without even the implied
>>> + * ************************
>>> + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>>> + * See the GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License
>>> + * along with GNU CC; see the file COPYING. If not, write to
>>> + * the Free Software Foundation, 59 Temple Place - Suite 330,
>>> + * Boston, MA 02111-1307, USA.
>>> + *
>>> + * Please send any bug reports or fixes you make to the
>>> + * email address(es):
>>> + * lksctp developers <lksctp-developers@lists.sourceforge.net>
>>> + *
>>> + * Or submit a bug report through the following website:
>>> + * http://www.sf.net/projects/lksctp
>>> + *
>>> + * Any bugs reported to us we will try to fix... any fixes shared will
>>> + * be incorporated into the next SCTP release.
>>> + *
>>> + * Written or modified by:
>>> + * Jon Grimm <jgrimm@us.ibm.com>
>>> + * Sridhar Samudrala <sri@us.ibm.com>
>>> + */
>>> +
>>> +/*
>>> + * This is a basic functional test for the SCTP kernel
>>> + * implementation of sndrcvinfo.sinfo_pr_value.
>>> + *
>>> + * 1) Create two sockets, the listening socket sets its RECVBUF small
>>> + * 2) Create a connection. Send enough data to the non-reading listener
>>> + * to fill the RCVBUF.
>>> + * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
>>> + * 6) Disable sinfo_pr_value on a message and send.
>>> + * 7) Wait sinfo_pr_value time.
>>> + * 8) Read out all the data at the receiver.
>>> + * 9) Make sure timed out message did not make it.
>>> + * 10) Make sure that the message with no timeout makes it to the receiver.
>>> + *
>>> + * Also test with SEND_FAILED notifications. Also, use a fragmented
>>> + * message so as to also exercise the SEND_FAILED of fragmentation
>>> + * code.
>>> + */
>>> +
>>> +#include <stdio.h>
>>> +#include <unistd.h>
>>> +#include <stdlib.h>
>>> +#include <string.h>
>>> +#include <sys/types.h>
>>> +#include <sys/socket.h>
>>> +#include <sys/uio.h>
>>> +#include <netinet/in.h>
>>> +#include <sys/errno.h>
>>> +#include <errno.h>
>>> +#include <netinet/sctp.h>
>>> +#include <sctputil.h>
>>> +
>>> +char *TCID = __FILE__;
>>> +int TST_TOTAL = 6;
>>> +int TST_CNT = 0;
>>> +
>>> +/* This is the size of our RCVBUF */
>>> +#define SMALL_RCVBUF 3000
>>> +
>>> +/* MAX segment size */
>>> +#define SMALL_MAXSEG 100
>>> +
>>> +/* RWND_SLOP is the extra data that fills up the rwnd */
>>> +#define RWND_SLOP 100
>>> +static char *fillmsg = NULL;
>>> +static char *ttlmsg = "This should time out!\n";
>>> +static char *nottlmsg = "This should NOT time out!\n";
>>> +static char ttlfrag[SMALL_MAXSEG*3] = {0};
>>> +static char *message = "Hello world\n";
>>> +
>>> +int main(int argc, char *argv[])
>>> +{
>>> + int sk1, sk2;
>>> + sockaddr_storage_t loop1;
>>> + sockaddr_storage_t loop2;
>>> + struct iovec iov;
>>> + struct msghdr inmessage;
>>> + struct msghdr outmessage;
>>> + char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))];
>>> + char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
>>> + struct cmsghdr *cmsg;
>>> + struct sctp_sndrcvinfo *sinfo;
>>> + struct iovec out_iov;
>>> + int error;
>>> + int pf_class, af_family;
>>> + uint32_t ppid;
>>> + uint32_t stream;
>>> + sctp_assoc_t associd1, associd2;
>>> + struct sctp_assoc_change *sac;
>>> + struct sctp_event_subscribe subscribe;
>>> + char *big_buffer;
>>> + int offset;
>>> + struct sctp_send_failed *ssf;
>>> + int len; /* Really becomes 2xlen when set. */
>>> + int orig_len;
>>> + struct sctp_status gstatus;
>>> +
>>> + /* Rather than fflush() throughout the code, set stdout to
>>> + * be unbuffered.
>>> + */
>>> + setvbuf(stdout, NULL, _IONBF, 0);
>>> +
>>> + /* Set some basic values which depend on the address family. */
>>> +#if TEST_V6
>>> + pf_class = PF_INET6;
>>> + af_family = AF_INET6;
>>> +
>>> + loop1.v6.sin6_family = AF_INET6;
>>> + loop1.v6.sin6_addr = in6addr_loopback;
>>> + loop1.v6.sin6_port = htons(SCTP_TESTPORT_1);
>>> +
>>> + loop2.v6.sin6_family = AF_INET6;
>>> + loop2.v6.sin6_addr = in6addr_loopback;
>>> + loop2.v6.sin6_port = htons(SCTP_TESTPORT_2);
>>> +#else
>>> + pf_class = PF_INET;
>>> + af_family = AF_INET;
>>> +
>>> + loop1.v4.sin_family = AF_INET;
>>> + loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
>>> + loop1.v4.sin_port = htons(SCTP_TESTPORT_1);
>>> +
>>> + loop2.v4.sin_family = AF_INET;
>>> + loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK;
>>> + loop2.v4.sin_port = htons(SCTP_TESTPORT_2);
>>> +#endif /* TEST_V6 */
>>> +
>>> + /* Create the two endpoints which will talk to each other. */
>>> + sk1 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
>>> + sk2 = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP);
>>> +
>>> + len = sizeof(int);
>>> + error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
>>> + &len);
>>> + if (error)
>>> + tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s",
>>> + strerror(errno));
>>> + /* Set the MAXSEG to something smallish. */
>>> + {
>>> + int val = SMALL_MAXSEG;
>>> + test_setsockopt(sk1, SCTP_MAXSEG, &val, sizeof(val));
>>> + }
>>> +
>>> + memset(&subscribe, 0, sizeof(subscribe));
>>> + subscribe.sctp_data_io_event = 1;
>>> + subscribe.sctp_association_event = 1;
>>> + subscribe.sctp_send_failure_event = 1;
>>> + test_setsockopt(sk1, SCTP_EVENTS, &subscribe, sizeof(subscribe));
>>> + test_setsockopt(sk2, SCTP_EVENTS, &subscribe, sizeof(subscribe));
>>> +
>>> + /* Bind these sockets to the test ports. */
>>> + test_bind(sk1, &loop1.sa, sizeof(loop1));
>>> + test_bind(sk2, &loop2.sa, sizeof(loop2));
>>> +
>>> + /*
>>> + * This code sets the associations RWND very small so we can
>>> + * fill it. It does this by manipulating the rcvbuf as follows:
>>> + * 1) Reduce the rcvbuf size on the socket
>>> + * 2) create an association so that we advertize rcvbuf/2 as
>>> + * our initial rwnd
>>> + * 3) raise the rcvbuf value so that we don't drop data wile
>>> + * receiving later data
>>> + */
>>> + len = SMALL_RCVBUF;
>>> + error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &len,
>>> + sizeof(len));
>>> + if (error)
>>> + tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
>>> + strerror(errno));
>>> +
>>> + /* Mark sk2 as being able to accept new associations. */
>>> + test_listen(sk2, 1);
>>> +
>>> + /* Send the first message. This will create the association. */
>>> + outmessage.msg_name = &loop2;
>>> + outmessage.msg_namelen = sizeof(loop2);
>>> + outmessage.msg_iov = &out_iov;
>>> + outmessage.msg_iovlen = 1;
>>> + outmessage.msg_control = outcmsg;
>>> + outmessage.msg_controllen = sizeof(outcmsg);
>>> + outmessage.msg_flags = 0;
>>> + cmsg = CMSG_FIRSTHDR(&outmessage);
>>> + cmsg->cmsg_level = IPPROTO_SCTP;
>>> + cmsg->cmsg_type = SCTP_SNDRCV;
>>> + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
>>> + outmessage.msg_controllen = cmsg->cmsg_len;
>>> + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>>> + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
>>> + ppid = rand(); /* Choose an arbitrary value. */
>>> + stream = 1;
>>> + sinfo->sinfo_ppid = ppid;
>>> + sinfo->sinfo_stream = stream;
>>> + outmessage.msg_iov->iov_base = message;
>>> + outmessage.msg_iov->iov_len = strlen(message) + 1;
>>> + test_sendmsg(sk1, &outmessage, 0, strlen(message)+1);
>>> +
>>> + /* Initialize inmessage for all receives. */
>>> + big_buffer = test_malloc(REALLY_BIG);
>>> + memset(&inmessage, 0, sizeof(inmessage));
>>> + iov.iov_base = big_buffer;
>>> + iov.iov_len = REALLY_BIG;
>>> + inmessage.msg_iov = &iov;
>>> + inmessage.msg_iovlen = 1;
>>> + inmessage.msg_control = incmsg;
>>> +
>>> + /* Get the communication up message on sk2. */
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>>> + test_check_msg_notification(&inmessage, error,
>>> + sizeof(struct sctp_assoc_change),
>>> + SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
>>> + sac = (struct sctp_assoc_change *)iov.iov_base;
>>> + associd2 = sac->sac_assoc_id;
>>> +
>>> + /* Get the communication up message on sk1. */
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
>>> + test_check_msg_notification(&inmessage, error,
>>> + sizeof(struct sctp_assoc_change),
>>> + SCTP_ASSOC_CHANGE, SCTP_COMM_UP);
>>> + sac = (struct sctp_assoc_change *)iov.iov_base;
>>> + associd1 = sac->sac_assoc_id;
>>> +
>>> + /* restore the rcvbuffer size for the receiving socket */
>>> + error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &orig_len,
>>> + sizeof(orig_len));
>>> +
>>> + if (error)
>>> + tst_brkm(TBROK, tst_exit, "setsockopt(SO_RCVBUF): %s",
>>> + strerror(errno));
>>> +
>>> + /* Get the first data message which was sent. */
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>>> + test_check_msg_data(&inmessage, error, strlen(message) + 1,
>>> + MSG_EOR, stream, ppid);
>>> +
>>> + /* Figure out how big to make our fillmsg */
>>> + len = sizeof(struct sctp_status);
>>> + memset(&gstatus,0,sizeof(struct sctp_status));
>>> + gstatus.sstat_assoc_id = associd1;
>>> + error = getsockopt(sk1, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
>>> +
>>> + if (error)
>>> + tst_brkm(TBROK, tst_exit, "can't get rwnd size: %s",
>>> + strerror(errno));
>>> + tst_resm(TINFO, "Creating fillmsg of size %d",
>>> + gstatus.sstat_rwnd+RWND_SLOP);
>>> + fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP);
>>> +
>>> + /* Send a fillmsg */
>>> + outmessage.msg_controllen = sizeof(outcmsg);
>>> + outmessage.msg_flags = 0;
>>> + cmsg = CMSG_FIRSTHDR(&outmessage);
>>> + cmsg->cmsg_level = IPPROTO_SCTP;
>>> + cmsg->cmsg_type = SCTP_SNDRCV;
>>> + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
>>> + outmessage.msg_controllen = cmsg->cmsg_len;
>>> + sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
>>> + memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
>>> + ppid++;
>>> + stream++;
>>> + sinfo->sinfo_ppid = ppid;
>>> + sinfo->sinfo_stream = stream;
>>> + memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP);
>>> + fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0';
>>> + outmessage.msg_iov->iov_base = fillmsg;
>>> + outmessage.msg_iov->iov_len = gstatus.sstat_rwnd+RWND_SLOP;
>>> + outmessage.msg_name = NULL;
>>> + outmessage.msg_namelen = 0;
>>> + sinfo->sinfo_assoc_id = associd1;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>>> + sinfo->sinfo_pr_value = 0;
>>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
>>> + gstatus.sstat_rwnd+RWND_SLOP);
>>> +
>>> + /* Now send the message with timeout. */
>>> + sinfo->sinfo_ppid = ppid;
>>> + sinfo->sinfo_stream = stream;
>>> + outmessage.msg_iov->iov_base = ttlmsg;
>>> + outmessage.msg_iov->iov_len = strlen(ttlmsg) + 1;
>>> + outmessage.msg_name = NULL;
>>> + outmessage.msg_namelen = 0;
>>> + sinfo->sinfo_assoc_id = associd1;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
>>> + sinfo->sinfo_pr_value = 2;
>>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
>>> +
>>> + tst_resm(TPASS, "Send a message with timeout");
>>> +
>>> + /* Next send a message with no timeout. */
>>> + sinfo->sinfo_ppid = ppid;
>>> + sinfo->sinfo_stream = stream;
>>> + outmessage.msg_iov->iov_base = nottlmsg;
>>> + outmessage.msg_iov->iov_len = strlen(nottlmsg) + 1;
>>> + outmessage.msg_name = NULL;
>>> + outmessage.msg_namelen = 0;
>>> + sinfo->sinfo_assoc_id = associd1;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>>> + sinfo->sinfo_pr_value = 0;
>>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
>>> +
>>> + tst_resm(TPASS, "Send a message with no timeout");
>>> +
>>> + /* And finally a fragmented message that will time out. */
>>> + sinfo->sinfo_ppid = ppid;
>>> + sinfo->sinfo_stream = stream;
>>> + memset(ttlfrag, '0', sizeof(ttlfrag));
>>> + ttlfrag[sizeof(ttlfrag)-1] = '\0';
>>> + outmessage.msg_iov->iov_base = ttlfrag;
>>> + outmessage.msg_iov->iov_len = sizeof(ttlfrag);
>>> + outmessage.msg_name = NULL;
>>> + outmessage.msg_namelen = 0;
>>> + sinfo->sinfo_assoc_id = associd1;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_RTX;
>>> + sinfo->sinfo_pr_value = 2;
>>> + test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
>>> +
>>> + tst_resm(TPASS, "Send a fragmented message with timeout");
>>> +
>>> + /* Sleep waiting for the message to time out. */
>>> + tst_resm(TINFO, " ** SLEEPING for 3 seconds **");
>>> + sleep(3);
>>> +
>>> + /* Read the fillmsg snuck in between the ttl'd messages. */
>>> + do {
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>>> + } while (!(inmessage.msg_flags & MSG_EOR));
>>> +
>>> + /* Now get the message that did NOT time out. */
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>>> + test_check_msg_data(&inmessage, error, strlen(nottlmsg) + 1,
>>> + MSG_EOR, stream, ppid);
>>> + if (0 != strncmp(iov.iov_base, nottlmsg, strlen(nottlmsg)+1))
>>> + tst_brkm(TBROK, tst_exit, "Received Wrong Message !!!");
>>> +
>>> + tst_resm(TPASS, "Receive message with no timeout");
>>> +
>>> + /* Get the SEND_FAILED notification for the message that DID
>>> + * time out.
>>> + */
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
>>> + test_check_msg_notification(&inmessage, error,
>>> + sizeof(struct sctp_send_failed) +
>>> + strlen(ttlmsg) + 1,
>>> + SCTP_SEND_FAILED, 0);
>>> + ssf = (struct sctp_send_failed *)iov.iov_base;
>>> + if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1))
>>> + tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
>>> +
>>> + tst_resm(TPASS, "Receive SEND_FAILED for message with timeout");
>>> +
>>> + /* Get the SEND_FAILED notification for the fragmented message that
>>> + * DID time out.
>>> + */
>>> + offset = 0;
>>> + do {
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk1, &inmessage, MSG_WAITALL);
>>> + test_check_msg_notification(&inmessage, error,
>>> + sizeof(struct sctp_send_failed) +
>>> + SMALL_MAXSEG,
>>> + SCTP_SEND_FAILED, 0);
>>> + ssf = (struct sctp_send_failed *)iov.iov_base;
>>> + if (0 != strncmp(&ttlfrag[offset], (char *)ssf->ssf_data,
>>> + SMALL_MAXSEG))
>>> + tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch");
>>> + offset += SMALL_MAXSEG;
>>> + } while (!(ssf->ssf_info.sinfo_flags & 0x01)); /* LAST_FRAG */
>>> +
>>> + tst_resm(TPASS, "Receive SEND_FAILED for fragmented message with "
>>> + "timeout");
>>> +
>>> + /* Shut down the link. */
>>> + close(sk1);
>>> +
>>> + /* Get the shutdown complete notification. */
>>> + inmessage.msg_controllen = sizeof(incmsg);
>>> + error = test_recvmsg(sk2, &inmessage, MSG_WAITALL);
>>> + test_check_msg_notification(&inmessage, error,
>>> + sizeof(struct sctp_assoc_change),
>>> + SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP);
>>> +
>>> + close(sk2);
>>> +
>>> + /* Indicate successful completion. */
>>> + return 0;
>>> +}
>>> diff --git a/src/func_tests/test_sctp_sendrecvmsg.c b/src/func_tests/test_sctp_sendrecvmsg.c
>>> index c275e45..aaa56e9 100644
>>> --- a/src/func_tests/test_sctp_sendrecvmsg.c
>>> +++ b/src/func_tests/test_sctp_sendrecvmsg.c
>>> @@ -243,7 +243,7 @@ int main(int argc, char *argv[])
>>> /* Now send a message that will timeout. */
>>> test_sctp_sendmsg(sk1, ttlmsg, strlen(ttlmsg) + 1,
>>> (struct sockaddr *)&loop2, sizeof(loop2),
>>> - ppid, 0, stream, 2000, 0);
>>> + ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
>>>
>>> tst_resm(TPASS, "sctp_sendmsg with ttl");
>>>
>>> @@ -259,7 +259,7 @@ int main(int argc, char *argv[])
>>> ttlfrag[sizeof(ttlfrag)-1] = '\0';
>>> test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag),
>>> (struct sockaddr *)&loop2, sizeof(loop2),
>>> - ppid, 0, stream, 2000, 0);
>>> + ppid, SCTP_PR_SCTP_TTL, stream, 2000, 0);
>>>
>>> tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl");
>>>
>>> @@ -335,7 +335,8 @@ int main(int argc, char *argv[])
>>> snd_sinfo.sinfo_ppid = rand();
>>> snd_sinfo.sinfo_flags = 0;
>>> snd_sinfo.sinfo_stream = 2;
>>> - snd_sinfo.sinfo_timetolive = 0;
>>> + snd_sinfo.sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>>> + snd_sinfo.sinfo_pr_value = 0;
>>> snd_sinfo.sinfo_assoc_id = associd1;
>>> test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo,
>>> MSG_NOSIGNAL);
>>> diff --git a/src/func_tests/test_timetolive.c b/src/func_tests/test_timetolive.c
>>> index d9bdf1b..dc66722 100644
>>> --- a/src/func_tests/test_timetolive.c
>>> +++ b/src/func_tests/test_timetolive.c
>>> @@ -39,14 +39,14 @@
>>>
>>> /*
>>> * This is a basic functional test for the SCTP kernel
>>> - * implementation of sndrcvinfo.sinfo_timetolive.
>>> + * implementation of sndrcvinfo.sinfo_pr_value.
>>> *
>>> * 1) Create two sockets, the listening socket sets its RECVBUF small
>>> * 2) Create a connection. Send enough data to the non-reading listener
>>> * to fill the RCVBUF.
>>> - * 5) Set sinfo_timetolive on a message and send.
>>> - * 6) Disable sinfo_timetolive on a message and send.
>>> - * 7) Wait sinfo_timetolive.
>>> + * 5) Set sinfo_pr_value with SCTP_PR_SCTP_TTL policy on a message and send.
>>> + * 6) Disable sinfo_pr_value on a message and send.
>>> + * 7) Wait sinfo_pr_value time.
>>> * 8) Read out all the data at the receiver.
>>> * 9) Make sure timed out message did not make it.
>>> * 10) Make sure that the message with no timeout makes it to the receiver.
>>> @@ -288,7 +288,8 @@ int main(int argc, char *argv[])
>>> outmessage.msg_name = NULL;
>>> outmessage.msg_namelen = 0;
>>> sinfo->sinfo_assoc_id = associd1;
>>> - sinfo->sinfo_timetolive = 0;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>>> + sinfo->sinfo_pr_value = 0;
>>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL,
>>> gstatus.sstat_rwnd+RWND_SLOP);
>>>
>>> @@ -300,7 +301,8 @@ int main(int argc, char *argv[])
>>> outmessage.msg_name = NULL;
>>> outmessage.msg_namelen = 0;
>>> sinfo->sinfo_assoc_id = associd1;
>>> - sinfo->sinfo_timetolive = 2000;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
>>> + sinfo->sinfo_pr_value = 2000;
>>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(ttlmsg) + 1);
>>>
>>> tst_resm(TPASS, "Send a message with timeout");
>>> @@ -313,7 +315,8 @@ int main(int argc, char *argv[])
>>> outmessage.msg_name = NULL;
>>> outmessage.msg_namelen = 0;
>>> sinfo->sinfo_assoc_id = associd1;
>>> - sinfo->sinfo_timetolive = 0;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>>> + sinfo->sinfo_pr_value = 0;
>>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, strlen(nottlmsg)+1);
>>>
>>> tst_resm(TPASS, "Send a message with no timeout");
>>> @@ -328,7 +331,8 @@ int main(int argc, char *argv[])
>>> outmessage.msg_name = NULL;
>>> outmessage.msg_namelen = 0;
>>> sinfo->sinfo_assoc_id = associd1;
>>> - sinfo->sinfo_timetolive = 2000;
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_TTL;
>>> + sinfo->sinfo_pr_value = 2000;
>>> test_sendmsg(sk1, &outmessage, MSG_NOSIGNAL, sizeof(ttlfrag));
>>>
>>> tst_resm(TPASS, "Send a fragmented message with timeout");
>>> diff --git a/src/include/netinet/sctp.h b/src/include/netinet/sctp.h
>>> index ae557a5..5a6cea2 100644
>>> --- a/src/include/netinet/sctp.h
>>> +++ b/src/include/netinet/sctp.h
>>> @@ -184,9 +184,10 @@ struct sctp_sndrcvinfo {
>>> __u16 sinfo_stream;
>>> __u16 sinfo_ssn;
>>> __u16 sinfo_flags;
>>> + __u16 sinfo_pr_policy;
>>> __u32 sinfo_ppid;
>>> __u32 sinfo_context;
>>> - __u32 sinfo_timetolive;
>>> + __u32 sinfo_pr_value;
>>> __u32 sinfo_tsn;
>>> __u32 sinfo_cumtsn;
>>> sctp_assoc_t sinfo_assoc_id;
>>> @@ -200,12 +201,25 @@ struct sctp_sndrcvinfo {
>>> */
>>>
>>> enum sctp_sinfo_flags {
>>> - SCTP_UNORDERED = 1, /* Send/receive message unordered. */
>>> - SCTP_ADDR_OVER = 2, /* Override the primary destination. */
>>> - SCTP_ABORT=4, /* Send an ABORT message to the peer. */
>>> - SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
>>> + SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */
>>> + SCTP_UNORDERED = 0x0400, /* Send/receive message unordered. */
>>> + SCTP_ADDR_OVER = 0x0800, /* Override the primary destination. */
>>> + SCTP_ABORT = 0x1000, /* Send an ABORT message to the peer. */
>>> };
>>>
>>> +/*
>>> + * sinfo_pr_policy: 16 bits (unsigned integer)
>>> + *
>>> + * This field may contain the partial reliability used to
>>> + * send the message.
>>> + */
>>> +
>>> +enum sctp_sinfo_pr_policy {
>>> + SCTP_PR_SCTP_NONE = 0x0000, /* Reliable transmission */
>>> + SCTP_PR_SCTP_TTL = 0x0001, /* Timed partial reliable */
>>> + SCTP_PR_SCTP_BUF = 0x0002, /* Buffer parital reliable */
>>> + SCTP_PR_SCTP_RTX = 0x0003, /* Retransmist partial reliable */
>>> +};
>>>
>>> typedef union {
>>> __u8 raw;
>>> @@ -816,7 +830,7 @@ int sctp_freeladdrs(struct sockaddr *addrs);
>>> */
>>> int sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
>>> socklen_t tolen, uint32_t ppid, uint32_t flags,
>>> - uint16_t stream_no, uint32_t timetolive, uint32_t context);
>>> + uint16_t stream_no, uint32_t pr_value, uint32_t context);
>>>
>>> /* This library function assist the user with sending a message without
>>> * dealing directly with the CMSG header.
>>> diff --git a/src/lib/sendmsg.c b/src/lib/sendmsg.c
>>> index 1de592d..a674646 100644
>>> --- a/src/lib/sendmsg.c
>>> +++ b/src/lib/sendmsg.c
>>> @@ -31,7 +31,7 @@
>>> int
>>> sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
>>> socklen_t tolen, uint32_t ppid, uint32_t flags,
>>> - uint16_t stream_no, uint32_t timetolive, uint32_t context)
>>> + uint16_t stream_no, uint32_t pr_value, uint32_t context)
>>> {
>>> struct msghdr outmsg;
>>> struct iovec iov;
>>> @@ -61,9 +61,22 @@ sctp_sendmsg(int s, const void *msg, size_t len, struct sockaddr *to,
>>> sinfo->sinfo_ppid = ppid;
>>> sinfo->sinfo_flags = flags;
>>> sinfo->sinfo_stream = stream_no;
>>> - sinfo->sinfo_timetolive = timetolive;
>>> sinfo->sinfo_context = context;
>>>
>>> + sinfo->sinfo_pr_policy = sinfo->sinfo_flags & 0xff;
>>> + sinfo->sinfo_pr_value = pr_value;
>>> +
>>> + printf("sinfo_flags: %x sinfo_pr_policy: %d sinfo_pr_value: %d\n",
>>> + sinfo->sinfo_flags, sinfo->sinfo_pr_policy, sinfo->sinfo_pr_value);
>>> +
>>> + /* If we get an invalid sinfo_pr_policy force it to
>>> + * SCTP_PR_SCTP_NONE or shall we better fail and set a
>>> + * EINVAL error??
>>> + */
>>> +
>>> + if(sinfo->sinfo_pr_policy > SCTP_PR_SCTP_RTX)
>>> + sinfo->sinfo_pr_policy = SCTP_PR_SCTP_NONE;
>>> +
>>> return sendmsg(s, &outmsg, 0);
>>> }
>>>
>>> diff --git a/src/testlib/sctputil.h b/src/testlib/sctputil.h
>>> index 347c91b..0afbc36 100644
>>> --- a/src/testlib/sctputil.h
>>> +++ b/src/testlib/sctputil.h
>>> @@ -270,11 +270,11 @@ static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
>>> static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
>>> struct sockaddr *to, socklen_t tolen,
>>> uint32_t ppid, uint32_t flags,
>>> - uint16_t stream_no, uint32_t timetolive,
>>> + uint16_t stream_no, uint32_t pr_value,
>>> uint32_t context)
>>> {
>>> int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
>>> - timetolive, context);
>>> + pr_value, context);
>>> if (len != error)
>>> tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
>>> error, errno);
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-12-16 14:33 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-03 1:59 [PATCH] Replace timetolive with pr_policy and pr_value Horacio Sanson
2008-12-03 7:15 ` Horacio Sanson
2008-12-15 9:56 ` Horacio Sanson
2008-12-15 15:55 ` Vlad Yasevich
2008-12-16 7:53 ` Horacio Sanson
2008-12-16 14:33 ` Vlad Yasevich
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.