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@xxxxxxxxx> 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 >
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;
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);
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);