lksctp-tools-1.0.16+dfsg.orig/0000755000175000017500000000000012300634451015677 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/INSTALL0000644000175000017500000000616412300634451016737 0ustar michaelmichael HOW TO COMPILE, RUN AND INSTALL ------------------------------- CONTENTS -------- The lksctp-tools package is intended for two audiences. 1) SCTP application developers 2) LKSCTP project developers For SCTP application developers, this package provides the user-level C language header files and a library for accessing SCTP specific application programming interfaces not provided by the standard sockets. For LKSCTP project developers, this package provides the functional and API regression tests. For either role, this project provides sample code, utilities, and tests that one may find useful. The below INSTALL directions are provided with in each of these roles. NOTE: To build, run and install the lksctp-tools package, your system is required to be running with linux-2.5.36, or a later version of the kernel, configured with the Network options "SCTP Configuration" support enabled. ______________________________________________________________________ INSTALLATION ------------- Prerequisite: A Linux kernel with SCTP support. This may come stock with your distrbution (some day), or you will need to build your own 2.5.36 or later kernel. To install/build the lksctp-tools utilities/tests do the following: 1) Download and install the following binary RPMs from the lksctp sourceforge website at http://sourceforge.net/project/showfiles.php?group_id=26529 * lksctp-tools-x.y.z-1.i386.rpm * lksctp-tools-x.y.z-devel-1.i386.rpm * lksctp-tools-x.y.z-doc-1.i386.rpm lksctp-tools-x.y.z-1.i386.rpm includes * SCTP run-time library. * Sample SCTP applications: sctp_darn and sctp_test. * withsctp: a tool when used with existing TCP binaries replaces TCP with SCTP. lksctp-tools-x.y.z-devel-1.i386.rpm includes * SCTP header file /usr/include/netinet/sctp.h * SCTP man pages. * Source code for sample SCTP applications. lksctp-tools-x.y.z-doc-1.i386.rpm includes * SCTP RFC's and internet drafts. If you want to run and play with the included sample SCTP applications or develop your own SCTP applications, you can skip the rest of the instructions. If you are interested in running the functional regression tests included in the lksctp-tools package, continue with the following instructions. 2) Download and install the following source RPM form the lksctp sourceforge website at http://sourceforge.net/project/showfiles.php?group_id=26529 * lksctp-tools-x.y.z-1.src.rpm This will install the lksctp-tools gzipped tarball and RPM spec file. 3) Untar the lksctp-tools directory from the gzipped tarball. This creates a subdirectory called lksctp-tools-x.y.z. Ensure you have autoconf, automake and libtool packages installed on your system. 4) Run ./bootstrap 5) Run ./configure 6) Run make 7) To run the SCTP kernel regression tests, $ cd src/func_tests $ make v4test (regression tests for the IPv4 socket support) $ make v6test (regression tests for the IPv6 socket support) 8) Run other SCTP test tools/applications in src/apps directory to verify the running SCTP. lksctp-tools-1.0.16+dfsg.orig/man/0000755000175000017500000000000012300634451016452 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/man/sctp_sendmsg.30000644000175000017500000000545712300634451021242 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_SENDMSG 3 2004-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_sendmsg \- Send a message from a SCTP socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_sendmsg(int " sd ", const void * " msg ", size_t " len , .BI " struct sockaddr *" to ", socklen_t " tolen , .BI " uint32_t " ppid ", uint32_t " flags , .BI " uint16_t " stream_no ", uint32_t " timetolive , .BI " uint32_t " context ); .fi .SH DESCRIPTION .BR sctp_sendmsg is a wrapper library function that can be used to send a message from a socket while using the advanced features of SCTP. .I sd is the socket descriptor from which the message pointed to by .I msg of length .I len is sent. .I to is the destination address of the message and .I tolen is the length of the destination address. .I stream_no identifies the stream number that the application wishes to send this message to. .I flags parameter is composed of a bitwise OR of the following values. .TP .B SCTP_UNORDERED This flags requests the un-ordered delivery of the message. .TP .B SCTP_ADDR_OVER This flag, in the one-to-many style, requests the SCTP stack to override the primary destination address with address specified in .I to. .TP .B SCTP_ABORT Setting this flag causes the specified association to abort by sending an ABORT message to the peer(one-to-many style only). The ABORT chunk will contain an error cause 'User Initiated Abort' with cause code 12. The cause specific information of this error cause is provided in .I msg. .TP .B SCTP_EOF Setting this flag invokes the SCTP graceful shutdown procedure on the specific association(one-to-many style only). .PP .I timetolive specifies the time duration in milliseconds. The sending side will expire the message if the message has not been sent to the peer within this time period. A value of 0 indicates that no timeout should occur on this message. .I ppid is an opaque unsigned value that is passed to the remote end along with the message. .I context is a 32 bit opaque value that is passed back to the upper layer along with the undelivered message if an error occurs on the send of the message. .SH "RETURN VALUE" On success, .BR sctp_sendmsg returns the number of bytes sent or -1 if an error occurred. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3), lksctp-tools-1.0.16+dfsg.orig/man/sctp_peeloff.30000644000175000017500000000323112300634451021206 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_PEELOFF 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_peeloff \- Branch off an association into a separate socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_peeloff(int " sd ", sctp_assoc_t " assoc_id ); .fi .SH DESCRIPTION .B sctp_peeloff branches off an existing association .I assoc_id on a one-to-many style socket .I sd into a separate socket. The new socket is a one-to-one style socket. .PP This is particularly desirable when, for instance, the application wishes to have a number of sporadic message senders/receivers remain under the original one-to-many style socket, but branch off those assocations carrying high volume data traffic into their own separate socket descriptors. .SH "RETURN VALUE" On success, the new socket descriptor representing the branched-off asociation is returned. On error, \-1 is returned, and .I errno is set appropriately. .SH ERRORS .TP .B EBADF .I sd is not a valid descriptor. .TP .B EINVAL The assoc id passed is invalid or if the socket is a one-to-one style socket. .TP .B ENOTSOCK Argument is a descriptor for a file, not a socket. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3), lksctp-tools-1.0.16+dfsg.orig/man/sctp.70000644000175000017500000004010412300634451017512 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP 7 2005-10-25 "Linux Man Page" "Linux Programmer's Manual" .SH NAME sctp \- SCTP protocol. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .B sctp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); .B sctp_socket = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); .fi .SH DESCRIPTION This is an implementation of the SCTP protocol as defined in RFC2960 and RFC3309. It is a message oriented, reliable transport protocol with direct support for multihoming that runs on top of .BR ip (7), and supports both v4 and v6 versions. .PP Like TCP, SCTP provides reliable, connection oriented data delivery with congestion control. Unlike TCP, SCTP also provides message boundary preservation, ordered and unordered message delivery, multi-streaming and multi-homing. Detection of data corruption, loss of data and duplication of data is achieved by using checksums and sequence numbers. A selective retransmission mechanism is applied to correct loss or corruption of data. .PP This implementation supports a mapping of SCTP into sockets API as defined in the draft-ietf-tsvwg-sctpsocket-10.txt(Sockets API extensions for SCTP). Two styles of interfaces are supported. .PP A .B one-to-many style interface with 1 to MANY relationship between socket and associations where the outbound association setup is implicit. The syntax of a one-to-many style socket() call is .PP .B sd = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); .PP A typical server in this style uses the following socket calls in sequence to prepare an endpoint for servicing requests. .PP 1. socket() 2. bind() 3. listen() 4. recvmsg() 5. sendmsg() 6. close() .PP A typical client uses the following calls in sequence to setup an association with a server to request services. .PP 1. socket() 2. sendmsg() 3. recvmsg() 4. close() .PP A .B one-to-one style interface with a 1 to 1 relationship between socket and association which enables existing TCP applications to be ported to SCTP with very little effort. The syntax of a one-to-one style socket() call is .PP .B sd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); .PP A typical server in one-to-one style uses the following system call sequence to prepare an SCTP endpoint for servicing requests: .PP 1. socket() 2. bind() 3. listen() 4. accept() .PP The accept() call blocks until a new association is set up. It returns with a new socket descriptor. The server then uses the new socket descriptor to communicate with the client, using recv() and send() calls to get requests and send back responses. Then it calls .PP 5. close() .PP to terminate the association. A typical client uses the following system call sequence to setup an association with a server to request services: .PP 1. socket() 2. connect() .PP After returning from connect(), the client uses send() and recv() calls to send out requests and receive responses from the server. The client calls .PP 3. close() .PP to terminate this association when done. .SH "ADDRESS FORMATS" SCTP is built on top of IP (see .BR ip (7)). The address formats defined by .BR ip (7) apply to SCTP. SCTP only supports point-to-point communication; broadcasting and multicasting are not supported. .SH SYSCTLS These variables can be accessed by the .B /proc/sys/net/sctp/* files or with the .BR sysctl (2) interface. In addition, most IP sysctls also apply to SCTP. See .BR ip (7). .TP .B addip_enable Enable SCTP ADDIP(Dynamic Address Reconfiguration) Support. This is off by default. .TP .B association_max_retrans Maximum number of consecutive retransmissions to a peer before an endpoint considers that the peer is unreachable and closes the association. The default value is 10. .TP .B cookie_preserve_enable Handle COOKIE PRESERVATIVE parameter in the INIT chunk. This is on by default. .TP .B hb_interval This is the interval when a HEARTBEAT chunk is sent to a destination transport address to monitor the reachability of an idle destination transport address. The default is 30 seconds and is maintained in msecs. .TP .B max_burst Maximum number of new data packets that can be sent in a burst. The default value is 4. .TP .B max_init_retransmits Maximum number of times an INIT chunk or a COOKIE ECHO chunk is retransmitted before an endpoint aborts the initialization process and closes the association. The default value is 8. .TP .B path_max_retrans Maximum number of consecutive retransmissions over a destination transport address of a peer endpoint before it is marked as inactive. The default value is 5. .TP .B prsctp_enable Enable PR-SCTP. This is on by default. .TP .B rcvbuf_policy This controls the socket receive buffer accounting policy. The default value is 0 and indicates that all the associations belonging to a socket share the same receive buffer space. When set to 1, each association will have its own receive buffer space. .TP .B rto_alpha_exp_divisor This is the RTO.Alpha value when expressed in right shifts and is used in RTO calculations. The default value is 3. .TP .B rto_beta_exp_divisor This is the RTO.Beta value when expressed in right shifts and is used in RTO calculations. The default value is 2. .TP .B rto_initial This is the initial value of RTO(retransmission timeout) that is used in RTO calculations. The default value is 3 seconds and is maintained in msecs. .TP .B rto_max This is the maximum value of RTO(retransmission timeout) that is used in RTO calculations. The default value is 60 seconds and is maintained in msecs. .TP .B rto_min This is the minimum value of RTO(retransmission timeout) that is used in RTO calculations. The default value is 1 second and is maintained in msecs. .TP .B sack_timeout Delayed SACK timeout. The default value is 200msecs. .TP .B sndbuf_policy This controls the socket sendbuffer accounting policy. The default value is 0 and indicates that all the associations belonging to a socket share the same send buffer space. When set to 1, each association will have its own send buffer space. .TP .B valid_cookie_life This is the maximum lifespan of the Cookie sent in an INIT ACK chunk. The default value is 60 secs and is maintained in msecs. .SH "STATISTICS" These variables can be accessed by the .B /proc/net/sctp/* files. .TP .B assocs Displays the following information about the active associations. assoc ptr, sock ptr, socket style, sock state, association state, hash bucket, association id, bytes in transmit queue, bytes in receive queue, user id, inode, local port, remote port, local addresses and remote addresses. .TP .B eps Displays the following information about the active endpoints. endpoint ptr, sock ptr, socket style, sock state, hash bucket, local port, user id, inode and local addresses. .TP .B snmp Displays the following statistics related to SCTP states, packets and chunks. .TP .TP .B SctpCurrEstab The number of associations for which the current state is either ESTABLISHED, SHUTDOWN-RECEIVED or SHUTDOWN-PENDING. .TP .B SctpActiveEstabs The number of times that associations have made a direct transition to the ESTABLISHED state from the COOKIE-ECHOED state. The upper layer initiated the association attempt. .TP .B SctpPassiveEstabs The number of times that associations have made a direct transition to the ESTABLISHED state from the CLOSED state. The remote endpoint initiated the association attempt. .TP .B SctpAborteds The number of times that associations have made a direct transition to the CLOSED state from any state using the primitive 'ABORT'. Ungraceful termination of the association. .TP .B SctpShutdowns The number of times that associations have made a direct transition to the CLOSED state from either the SHUTDOWN-SENT state or the SHUTDOWN-ACK-SENT state. Graceful termination of the association. .TP .B SctpOutOfBlues The number of out of the blue packets received by the host. An out of the blue packet is an SCTP packet correctly formed, including the proper checksum, but for which the receiver was unable to identify an appropriate association. .TP .B SctpChecksumErrors The number of SCTP packets received with an invalid checksum. .TP .B SctpOutCtrlChunks The number of SCTP control chunks sent (retransmissions are not included). Control chunks are those chunks different from DATA. .TP .B SctpOutOrderChunks The number of SCTP ordered data chunks sent (retransmissions are not included). .TP .B SctpOutUnorderChunks The number of SCTP unordered chunks(data chunks in which the U bit is set to 1) sent (retransmissions are not included). .TP .B SctpInCtrlChunks The number of SCTP control chunks received (no duplicate chunks included). .TP .B SctpInOrderChunks The number of SCTP ordered data chunks received (no duplicate chunks included). .TP .B SctpInUnorderChunks The number of SCTP unordered chunks(data chunks in which the U bit is set to 1) received (no duplicate chunks included). .TP .B SctpFragUsrMsgs The number of user messages that have to be fragmented because of the MTU. .TP .B SctpReasmUsrMsgs The number of user messages reassembled, after conversion into DATA chunks. .TP .B SctpOutSCTPPacks The number of SCTP packets sent. Retransmitted DATA chunks are included. .TP .B SctpInSCTPPacks The number of SCTP packets received. Duplicates are included. .SH "SOCKET OPTIONS" To set or get a SCTP socket option, call .BR getsockopt (2) to read or .BR setsockopt (2) to write the option with the option level argument set to .BR SOL_SCTP. .TP .BR SCTP_RTOINFO. This option is used to get or set the protocol parameters used to initialize and bound retransmission timout(RTO). The structure sctp_rtoinfo defined in /usr/include/netinet/sctp.h is used to access and modify these parameters. .TP .B SCTP_ASSOCINFO This option is used to both examine and set various association and endpoint parameters. The sturcture sctp_assocparams defined in /usr/include/netinet/sctp.h is used to access and modify these parameters. .TP .B SCTP_INITMSG This option is used to get or set the protocol parameters for the default association initialization. The structure sctp_initmsg defined in /usr/include/netinet/sctp.h is used to access and modify these parameters. Setting initialization parameters is effective only on an unconnected socket (for one-to-many style sockets only future associations are effected by the change). With one-to-one style sockets, this option is inherited by sockets derived from a listener socket. .TP .B SCTP_NODELAY Turn on/off any Nagle-like algorithm. This means that packets are generally sent as soon as possible and no unnecessary delays are introduced, at the cost of more packets in the network. Expects an integer boolean flag. .TP .B SCTP_AUTOCLOSE This socket option is applicable to the one-to-many style socket only. When set it will cause associations that are idle for more than the specified number of seconds to automatically close. An association being idle is defined an association that has NOT sent or received user data. The special value of 0 indicates that no automatic close of any associations should be performed. The option expects an integer defining the number of seconds of idle time before an association is closed. .TP .B SCTP_SET_PEER_PRIMARY_ADDR Requests that the peer mark the enclosed address as the association primary. The enclosed address must be one of the association's locally bound addresses. The structure sctp_setpeerprim defined in /usr/include/netinet/sctp.h is used to make a set peer primary request. .TP .B SCTP_PRIMARY_ADDR Requests that the local SCTP stack use the enclosed peer address as the association primary. The enclosed address must be one of the association peer's addresses. The structure sctp_prim defined in /usr/include/netinet/sctp.h is used to make a get/set primary request. .TP .B SCTP_DISABLE_FRAGMENTS This option is a on/off flag and is passed an integer where a non-zero is on and a zero is off. If enabled no SCTP message fragmentation will be performed. Instead if a message being sent exceeds the current PMTU size, the message will NOT be sent and an error will be indicated to the user. .TP .B SCTP_PEER_ADDR_PARAMS Using this option, applications can enable or disable heartbeats for any peer address of an association, modify an address's heartbeat interval, force a heartbeat to be sent immediately, and adjust the address's maximum number of retransmissions sent before an address is considered unreachable. The structure sctp_paddrparams defined in /usr/include/netinet/sctp.h is used to access and modify an address's parameters. .TP .B SCTP_DEFAULT_SEND_PARAM Applications that wish to use the sendto() system call may wish to specify a default set of parameters that would normally be supplied through the inclusion of ancillary data. This socket option allows such an application to set the default sctp_sndrcvinfo structure. The application that wishes to use this socket option simply passes in to this call the sctp_sndrcvinfo structure defined in /usr/include/netinet/sctp.h. The input parameters accepted by this call include sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context, sinfo_timetolive. The user must set the sinfo_assoc_id field to identify the association to affect if the caller is using the one-to-many style. .TP .B SCTP_EVENTS This socket option is used to specify various notifications and ancillary data the user wishes to receive. The structure sctp_event_subscribe defined in /usr/include/netinet/sctp.h is used to access or modify the events of interest to the user. .TP .B SCTP_I_WANT_MAPPED_V4_ADDR This socket option is a boolean flag which turns on or off mapped V4 addresses. If this option is turned on and the socket is type PF_INET6, then IPv4 addresses will be mapped to V6 representation. If this option is turned off, then no mapping will be done of V4 addresses and a user will receive both PF_INET6 and PF_INET type addresses on the socket. By default this option is turned on and expects an integer to be passed where non-zero turns on the option and zero turns off the option. .TP .B SCTP_MAXSEG This socket option specifies the maximum size to put in any outgoing SCTP DATA chunk. If a message is larger than this size it will be fragmented by SCTP into the specified size. Note that the underlying SCTP implementation may fragment into smaller sized chunks when the PMTU of the underlying association is smaller than the value set by the user. The option expects an integer. The default value for this option is 0 which indicates the user is NOT limiting fragmentation and only the PMTU will effect SCTP's choice of DATA chunk size. .TP .B SCTP_STATUS Applications can retrieve current status information about an association, including association state, peer receiver window size, number of unacked data chunks, and number of data chunks pending receipt. This information is read-only. The structure sctp_status defined in /usr/include/netinet/sctp.h is used to access this information. .TP .B SCTP_GET_PEER_ADDR_INFO Applications can retrieve information about a specific peer address of an association, including its reachability state, congestion window, and retransmission timer values. This information is read-only. The structure sctp_paddr_info defined in /usr/include/netinet/sctp.h is used to access this information. .TP .B SCTP_GET_ASSOC_STATS Applications can retrieve current statistics about an association, including SACKs sent and received, SCTP packets sent and received. The complete list can be found in /usr/include/netinet/sctp.h in struct sctp_assoc_stats. .SH AUTHORS Sridhar Samudrala .SH "SEE ALSO" .BR socket (7), .BR socket (2), .BR ip (7), .BR bind (2), .BR listen (2), .BR accept (2), .BR connect (2), .BR sendmsg (2), .BR recvmsg (2), .BR sysctl (2), .BR getsockopt (2), .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getladdrs (3), .BR sctp_getpaddrs (3), .BR sctp_opt_info (3). .sp RFC2960, RFC3309 for the SCTP specification. lksctp-tools-1.0.16+dfsg.orig/man/sctp_getladdrs.30000644000175000017500000000401612300634451021541 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_GETLADDRS 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_getladdrs \- Returns all locally bound addresses on a socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_getladdrs(int " sd ", sctp_assoc_t " assoc_id , .BI " struct sockaddr **" addrs ); .sp .BI "void sctp_freeladdrs(struct sockaddr *" addrs ); .fi .SH DESCRIPTION .BR sctp_getladdrs returns all locally bound addresses on a socket. On return, .I addrs will point to a dynamically allocated packed array of .B sockaddr structures of the appropriate type for each local address. The caller should use .BR sctp_freeladdrs to free the memory. Note that the in/out parameter .I addrs must not be NULL. .PP If .I sd is an IPv4 socket, the addresses returned will be all IPv4 addresses. If .I sd is an IPv6 socket, the addresses returned can be a mix of IPv4 or IPv6 addresses. .PP For one-to-many style sockets, .I id specifies the association to query. For one-to-one style sockets, .I id is ignored. .PP If the .I id field is set to 0, then the locally bound addresses are returned without regard to any particular association. .PP .BR sctp_freeladdrs frees all the resources allocated by .BR sctp_getladdrs .SH "RETURN VALUE" On success, .BR sctp_getladdrs returns the number of local addresses bound to the socket. If the socket is unbound, 0 is returned and the value of .I *addrs is undefined. On error, .BR sctp_getladdrs returns -1 and the value of .I *addrs is undefined. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_opt_info (3), lksctp-tools-1.0.16+dfsg.orig/man/sctp_bindx.30000644000175000017500000000465412300634451020704 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_BINDX 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_bindx \- Add or remove bind addresses on a socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_bindx(int " sd ", struct sockaddr * " addrs ", int " addrcnt , .BI " int " flags ); .fi .SH DESCRIPTION .BR sctp_bindx adds or removes a set of bind addresses passed in the array .I addrs to/from the socket .I sd. .I addrcnt is the number of addresses in the array and the .I flags paramater indicates if the addresses need to be added or removed. .PP If .I sd is an IPv4 socket, the addresses passed must be IPv4 addresses. If .I sd is an IPv6 socket, the addresses passed can be either IPv4 or IPv6 addresses. .PP .I addrs is a pointer to an array of one or more socket addresses. Each address is contained in its appropriate structure(i.e. struct sockaddr_in or struct sockaddr_in6). The family of the address type must be used to distinguish the address length. The caller specifies the number of addresses in the array with .I addrcnt. .PP The .I flags parameter can be either .B SCTP_BINDX_ADD_ADDR or .B SCTP_BINDX_REM_ADDR. An application can use .B SCTP_BINDX_ADD_ADDR to associate additional addresses with an endpoint after calling .BR bind(2). .B SCTP_BINDX_REM_ADDR directs SCTP to remove the given addresses from the association. A caller may not remove all addresses from an association. It will fail with .B EINVAL. .SH "RETURN VALUE" On success, 0 is returned. On failure, \-1 is returned, and .I errno is set appropriately. .SH ERRORS .TP .B EBADF .I sd is not a valid descriptor. .TP .B ENOTSOCK .I sd is a descriptor for a file, not a socket. .TP .B EFAULT Error while copying in or out from the user address space. .TP .B EINVAL Invalid port or address or trying to remove all addresses from an association. .TP .B EACCES The address is protected, and the user is not the super-user. .SH "SEE ALSO" .BR sctp (7) .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3), .BR sctp_connectx (3) lksctp-tools-1.0.16+dfsg.orig/man/sctp_opt_info.30000644000175000017500000000310012300634451021376 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_OPT_INFO 3 2004-01-30 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_optinfo \- Get options on a SCTP socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_opt_info(int " sd ", sctp_assoc_t " id ", int " opt , .BI " void * " arg ", socklen_t * " size); .fi .SH DESCRIPTION .BR sctp_opt_info is a wrapper library function that can be used to get SCTP level options on a socket. .I sd is the socket descriptor for which the option is requested. For one-to-many style sockets, .I id specifies the association to query. For one-to-one style sockets, .I id is ignored. .I opt specifes the SCTP socket option to get. .I arg is an option-specific structure buffer provided by the caller. .I size is a value-result parameter, initially containing the size of the buffer pointed to by .I arg and modifed on return to indicate the actual size of the value returned. .SH "RETURN VALUE" On success, .BR sctp_opt_info returns 0 and on failure -1 is returned with errno set to the appropriate error code. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), lksctp-tools-1.0.16+dfsg.orig/man/sctp_getpaddrs.30000644000175000017500000000362112300634451021546 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_GETPADDRS 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_getpaddrs \- Returns all peer addresses in an association. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_getpaddrs(int " sd ", sctp_assoc_t " assoc_id , .BI " struct sockaddr **" addrs ); .sp .BI "void sctp_freepaddrs(struct sockaddr *" addrs ); .fi .SH DESCRIPTION .BR sctp_getpaddrs returns all peer addresses in an association. On return, .I addrs will point to a dynamically allocated packed array of .B sockaddr structures of the appropriate type for each address. The caller should use .BR sctp_freepaddrs to free the memory. Note that the in/out parameter .I addrs must not be NULL. .PP If .I sd is an IPv4 socket, the addresses returned will be all IPv4 addresses. If .I sd is an IPv6 socket, the addresses returned can be a mix of IPv4 or IPv6 addresses. .PP For one-to-many style sockets, .I id specifies the association to query. For one-to-one style sockets, .I id is ignored. .PP .BR sctp_freepaddrs frees all the resources allocated by .BR sctp_getpaddrs. .SH "RETURN VALUE" On success, .BR sctp_getpaddrs returns the number of peer addresses in the association. If there is no association on this socket, 0 is returned and the value of .I *addrs is undefined. On error, .BR sctp_getpaddrs returns -1 and the value of .I *addrs is undefined. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3), lksctp-tools-1.0.16+dfsg.orig/man/sctp_send.30000644000175000017500000000263412300634451020525 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_SEND 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_send \- Send a message from a SCTP socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_send(int " sd ", const void * " msg ", size_t " len , .BI " const struct sctp_sndrcvinfo *" sinfo ", .BI " uint32_t " flags ); .fi .SH DESCRIPTION .BR sctp_send is a wrapper library function that can be used to send a message from a socket without the use of the CMSG header structures. .I sd is the socket descriptor from which the message pointed to by .I msg of length .I len is sent. .I sinfo is a pointer to a sctp_sndrcvinfo structure. .I flags parameter is composed of a bitwise OR of the flags that can be be passed as the 3rd argument of a standard sendmsg() call. .SH "RETURN VALUE" On success, .BR sctp_sendmsg returns the number of bytes sent or -1 if an error occurred. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3), .BR sctp_sendmsg (3) lksctp-tools-1.0.16+dfsg.orig/man/Makefile.am0000644000175000017500000000046612300634451020514 0ustar michaelmichael# -*- Makefile -*- # include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules man7_MANS = sctp.7 man3_MANS = sctp_bindx.3 sctp_getladdrs.3 sctp_getpaddrs.3 sctp_opt_info.3 \ sctp_peeloff.3 sctp_recvmsg.3 sctp_sendmsg.3 sctp_connectx.3 \ sctp_send.3 EXTRA_DIST += $(man3_MANS) $(man7_MANS) lksctp-tools-1.0.16+dfsg.orig/man/sctp_connectx.30000644000175000017500000000711512300634451021414 0ustar michaelmichael.\" (C) Copyright Frank Filz IBM Corp. 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_CONNECTX 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_connectx \- initiate a connection on an SCTP socket using multiple destination addresses. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_connectx(int " sd ", struct sockaddr * " addrs ", int " addrcnt, .BI " sctp_assoc_t * "id ); .fi .SH DESCRIPTION .BR sctp_connectx initiates a connection to a set of addresses passed in the array .I addrs to/from the socket .I sd. .I addrcnt is the number of addresses in the array. .PP If .I sd is an IPv4 socket, the addresses passed must be IPv4 addresses. If .I sd is an IPv6 socket, the addresses passed can be either IPv4 or IPv6 addresses. .PP .I addrs is a pointer to an array of one or more socket addresses. Each address is contained in its appropriate structure(i.e. struct sockaddr_in or struct sockaddr_in6). The family of the address type must be used to distinguish the address length. The caller specifies the number of addresses in the array with .I addrcnt. .PP .I id is a pointer to the association id and, if provided, will be set to the identifier of the newly created association. .SH "RETURN VALUE" On success, 0 is returned. On failure, \-1 is returned, and .I errno is set appropriately. .SH ERRORS .TP .B EBADF .I sd is not a valid descriptor. .TP .B ENOTSOCK .I sd is a descriptor for a file, not a socket. .TP .B EFAULT Error while copying in or out from the user address space. .TP .B EINVAL Invalid port or address. .TP .B EACCES The address is protected, and the user is not the super-user. .TP .B EISCONN The socket is already connected. .TP .B ECONNREFUSED No one listening on the remote address. .TP .B ETIMEDOUT Timeout while attempting connection. The server may be too busy to accept new connections. Note that for IP sockets the timeout may be very long when syncookies are enabled on the server. .TP .B ENETUNREACH Network is unreachable. .TP .B EADDRINUSE Local address is already in use. .TP .B EINPROGRESS The socket is non-blocking and the connection cannot be completed immediately. It is possible to .BR select (2) or .BR poll (2) for completion by selecting the socket for writing. After .B select indicates writability, use .BR getsockopt (2) to read the .B SO_ERROR option at level .B SOL_SOCKET to determine whether .B connect completed successfully .RB ( SO_ERROR is zero) or unsuccessfully .RB ( SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure). .TP .B EALREADY The socket is non-blocking and a previous connection attempt has not yet been completed. .TP .B EAGAIN No more free local ports or insufficient entries in the routing cache. For .B PF_INET see the .B net.ipv4.ip_local_port_range sysctl in .BR ip (7) on how to increase the number of local ports. .TP .B EAFNOSUPPORT The passed address didn't have the correct address family in its .I sa_family field. .TP .B EACCES, EPERM The user tried to connect to a broadcast address without having the socket broadcast flag enabled or the connection request failed because of a local firewall rule. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_recvmsg (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3), lksctp-tools-1.0.16+dfsg.orig/man/sctp_recvmsg.30000644000175000017500000000343512300634451021242 0ustar michaelmichael.\" (C) Copyright Sridhar Samudrala IBM Corp. 2004, 2005. .\" .\" Permission is granted to distribute possibly modified copies .\" of this manual provided the header is included verbatim, .\" and in case of nontrivial modification author and date .\" of the modification is added to the header. .\" .TH SCTP_RECVMSG 3 2005-10-25 "Linux 2.6" "Linux Programmer's Manual" .SH NAME sctp_recvmsg \- Receive a message from a SCTP socket. .SH SYNOPSIS .nf .B #include .B #include .B #include .sp .BI "int sctp_recvmsg(int " sd ", void * " msg ", size_t " len , .BI " struct sockaddr * " from ", socklen_t * " fromlen , .BI " struct sctp_sndrcvinfo * " sinfo ", int * " msg_flags); .fi .SH DESCRIPTION .BR sctp_recvmsg is a wrapper library function that can be used to receive a message from a socket while using the advanced features of SCTP. .I sd is the socket descriptor on which the message pointed to by .I msg of length .I len is received. .PP If .I from is not NULL, the source address of the message is filled in. The argument .I fromlen is a value-result parameter. initialized to the size of the buffer associated with .I from , and modified on return to indicate the actual size of the address stored. .PP .I sinfo is a pointer to a sctp_sndrcvinfo structure to be filled upon receipt of the message. .I msg_flags is a pointer to a integer that is filled with any message flags like .B MSG_NOTIFICATION or .B MSG_EOR. .SH "RETURN VALUE" On success, .BR sctp_recvmsg returns the number of bytes received or -1 if an error occurred. .SH "SEE ALSO" .BR sctp (7) .BR sctp_bindx (3), .BR sctp_connectx (3), .BR sctp_sendmsg (3), .BR sctp_send (3), .BR sctp_peeloff (3), .BR sctp_getpaddrs (3), .BR sctp_getladdrs (3), .BR sctp_opt_info (3) lksctp-tools-1.0.16+dfsg.orig/Makefile.dirs0000644000175000017500000000261612300634451020304 0ustar michaelmichael# -*-makefile-*- # # Define here directories you want rootbindir = /bin rootsbindir = /sbin rootlibdir = /lib localedir = $(datadir)/locale pkgsysconfdir = $(sysconfdir)/@PACKAGE@ pkgdocdir = $(datadir)/@PACKAGE@ vpkgsysconfdir = $(pkgsysconfdir)/v@VERSION@ vpkgdatadir = $(pkgdatadir)/v@VERSION@ vpkglibdir = $(pkglibdir)/v@VERSION@ vpkgdocdir = $(docdir)/v@VERSION@ # List here all the directories you want listed in the file to be used # in your programs: directories := \ localedir \ pkgsysconfdir \ rootbindir \ rootlibdir \ rootsbindir \ vpkgdatadir \ vpkgdocdir \ vpkglibdir \ vpkgsysconfdir \ \ bindir \ datadir \ libdir \ pkgdatadir \ pkgdocdir \ pkglibdir \ sbindir # To modify this target for another language, just copy, paste and # modify the target to generate directories.h. We depend on # config.status and Makefile.dirs, as anything changed is going to be # reflected there. # This is for generating the list in C/C++ directories.h: $(top_builddir)/config.status $(top_srcdir)/Makefile.dirs @rm -f $@ @echo -n "Creating $@ ..." @echo "#ifndef __$(subst .,_,$@)__" > $@ @echo "# define __$(subst .,_,$@)__" >> $@ @echo "" >> $@ @echo -e $(foreach v,$(directories),$(shell echo 'D_$(v) \"$($v)\"\\n')) \ | sed 's/^ *D_/# define D_/' >> $@ @echo "#endif" >> $@ @echo " done" DISTCLEANFILES += directories.h MAINTAINERCLEANFILES += directories.h ## FIXME: Your stuff here lksctp-tools-1.0.16+dfsg.orig/lksctp-tools.spec.in0000644000175000017500000001205612300634451021622 0ustar michaelmichael# -*- rpm-spec -*- # # lksctp-tools.spec.in --- RPM'ed lksctp-tools # Author : Francois-Xavier Kowalski # Created On : Sat Jan 10 14:53:53 2004 # Last Modified By: Vlad Yasevich # Last Modified On: Tue Jan 08 10:56 EDT 2013 # # (c) Copyright Hewlett-Packard Company 2004 # (C) Copyright IBM Corp. 2004 # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License v2 as published by the Free Software Foundation; only # version 2 of the License is valid for this software, unless # explicitly otherwise stated. # # This software 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 v2 along with this program; if not, write to the # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, # MA 02139, USA. %define lksctp_version @VERSION@ # older lksctp-tools file name did not conform to RPM file naming # conventions %define pack_version %{lksctp_version} %define file_version %{lksctp_version} Summary: User-space access to Linux Kernel SCTP Name: @PACKAGE@ Version: %{pack_version} Release: 1 License: LGPL Group: System Environment/Libraries URL: http://lksctp.sourceforge.net Source0: %{name}-%{file_version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot BuildRequires: gcc #BuildRequires: tetex, tetex-latex, tetex-xdvi, tetex-dvips #BuildRequires: ghostscript, enscript BuildRequires: libtool, automake, autoconf %description This is the lksctp-tools package for Linux Kernel SCTP Reference Implementation. This package is intended to supplement the Linux Kernel SCTP Reference Implementation now available in the Linux kernel source tree in versions 2.5.36 and following. For more information on LKSCTP see the package documentation README file, section titled "LKSCTP - Linux Kernel SCTP." This package contains the base run-time library & command-line tools. %package devel Summary: Development kit for lksctp-tools Group: Development/Libraries Requires: %{name} = %{version} Requires: glibc-devel %description devel Development kit for lksctp-tools - Man pages - Header files - Static libraries - Symlinks to dynamic libraries - Tutorial source code %package doc Summary: Documents pertaining to SCTP Group: System Environment/Libraries Requires: %{name} = %{version} %description doc Documents pertaining to LKSCTP & SCTP in general - IETF RFC's & Internet Drafts %prep %setup -q -n %{name}-%{file_version} %build %configure --enable-shared --enable-static make %install rm -rf $RPM_BUILD_ROOT make install DESTDIR="$RPM_BUILD_ROOT" %clean rm -rf $RPM_BUILD_ROOT %post /sbin/ldconfig %postun /sbin/ldconfig %files %defattr(-,root,root,-) %doc AUTHORS COPYING ChangeLog COPYING.lib %{_bindir}/* %{_libdir}/libsctp.so.* %{_libdir}/@PACKAGE@/* %files devel %defattr(-,root,root,-) %{_includedir} %{_libdir}/libsctp.so %{_libdir}/libsctp.a %{_libdir}/libsctp.la %{_datadir}/@PACKAGE@/* %{_mandir}/* %files doc %defattr(-,root,root,-) %doc doc/*.txt %changelog * Tue Feb 18 2014 Daniel Borkmann 1.0.16-1 - 1.0.16 Release * Sun May 12 2013 Daniel Borkmann 1.0.15-1 - 1.0.15 Release * Wed Apr 05 2013 Daniel Borkmann 1.0.14-1 - 1.0.14 Release * Wed Jan 23 2013 Daniel Borkmann 1.0.13-1 - 1.0.13 Release * Tue Jan 08 2013 Vlad Yasevich 1.0.12-1 - 1.0.12 Release * Wed Oct 21 2009 Vlad Yasevich 1.0.11-1 - 1.0.11 Release * Fri Mar 27 2009 Vlad Yasevich 1.0.10-1 - 1.0.10 Release * Sun Jun 13 2008 Vlad Yasevich 1.0.9-1 - 1.0.9 Release * Fri Feb 01 2008 Vlad Yasevich 1.0.8-1 - 1.0.8 Release * Fri Jun 29 2007 Vlad Yasevich 1.0.7-1 - 1.0.7 Release * Fri Feb 3 2006 Sridhar Samudrala 1.0.6-1 - 1.0.6 Release * Tue Jan 3 2006 Sridhar Samudrala 1.0.5-1 - 1.0.5 Release * Fri Oct 28 2005 Sridhar Samudrala 1.0.4-1 - 1.0.4 Release * Thu Sep 1 2005 Sridhar Samudrala 1.0.3-1 - 1.0.3 Release * Thu Dec 30 2004 Sridhar Samudrala 1.0.2-1 - 1.0.2 Release * Tue May 11 2004 Sridhar Samudrala 1.0.1-1 - 1.0.1 Release * Thu Feb 26 2004 Sridhar Samudrala 1.0.0-1 - 1.0.0 Release * Fri Feb 6 2004 Francois-Xavier Kowalski 0.9.0-1 - package only .txt doc files * Wed Feb 4 2004 Francois-Xavier Kowalski 0.7.5-1 - badly placed & undelivered files - simplified delivery list * Tue Jan 27 2004 Francois-Xavier Kowalski 0.7.5-1 - Integrate comment from project team * Sat Jan 10 2004 Francois-Xavier Kowalski 2.6.0_test7_0.7.4-1 - Creation lksctp-tools-1.0.16+dfsg.orig/configure.ac0000644000175000017500000000353312300634451020171 0ustar michaelmichaeldnl -*-autoconf-*- dnl lksctp-tools: Autoconf script dnl dnl $Id: configure.in,v 1.1.1.2 2002/08/06 23:55:45 inaky Exp $ dnl (C) 2002 Intel Corporation dnl Iñaky Pérez-González dnl - Initial packaging dnl Package info dnl (CONFIG_AUX_DIR is for putting stuff in $TOPSRCDIR/bin, so we dnl reduce clutter in the root; if we put it below AM_INIT_AUTOMAKE, dnl configure will fail ...) AC_INIT([lksctp-tools], [1.0.16], [], [], [http://www.lksctp.org/]) AC_CONFIG_AUX_DIR(bin) AC_CONFIG_SRCDIR([src/apps/sctp_darn.c]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_REVISION($Revision: 1.1.1.2 $) AM_INIT_AUTOMAKE m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])]) AM_SILENT_RULES([yes]) dnl Set defaults dnl CFLAGS="$CFLAGS -g -Wall" dnl Checks for programs. AC_PROG_AWK AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_ISC_POSIX dnl Checks for libraries. AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL AC_SUBST(LIBTOOL_DEPS) dnl Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h netdb.h netinet/in.h stdint.h stdlib.h string.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h]) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_C_INLINE AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM AC_C_VOLATILE # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_REALLOC AC_FUNC_SELECT_ARGTYPES AC_FUNC_SETVBUF_REVERSED AC_FUNC_VPRINTF AC_CHECK_FUNCS([bzero gethostbyname gettimeofday memmove memset select socket strchr strerror strtol strtoul]) AC_CONFIG_FILES([lksctp-tools.spec Makefile bin/Makefile man/Makefile src/Makefile src/apps/Makefile src/func_tests/Makefile src/include/Makefile src/include/netinet/Makefile src/lib/Makefile src/testlib/Makefile src/withsctp/Makefile doc/Makefile]) AC_OUTPUT lksctp-tools-1.0.16+dfsg.orig/src/0000755000175000017500000000000012300634451016466 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/withsctp/0000755000175000017500000000000012300634451020333 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/withsctp/sctp_socket.c0000644000175000017500000000443012300634451023021 0ustar michaelmichael/* Wrap socket() to force the protocol to SCTP for STREAM connections. * * Thanks to Midgard Security Services for * http://www.securiteam.com/tools/3D5PTR5QAE.html * from whence I cribbed the code to find the old socket(). * * gcc sctp_socket.c -o sctp_socket.so -ldl -shared -O2 -s * export LD_PRELOAD=./sctp_socket.so * * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* for strncmp() */ #include #include "sctp_socket.h" /* IPPROTO_SCTP SHOULD be defined in * /usr/include/linux/in.h but probably isn't. * It is an enum element, not a #define, so we can't easily check. */ #define SHOULD_IPPROTO_SCTP 132 int socket(int domain, int type, int protocol) { _sctp_load_libs(); if (((PF_INET == domain) || (PF_INET6 == domain)) && (SOCK_STREAM == type)) { protocol = SHOULD_IPPROTO_SCTP; } return (real_socket)(domain, type, protocol); } lksctp-tools-1.0.16+dfsg.orig/src/withsctp/withsctp.in0000644000175000017500000000032112300634451022524 0ustar michaelmichael#!/bin/sh # -*- sh -*- LIBDIR=@libdir@/@PACKAGE@ BINDIR=@bindir@ export LD_PRELOAD=${LIBDIR}/libwithsctp.so.1.0.16 if ! ${BINDIR}/checksctp 2> /dev/null then ${BINDIR}/checksctp; exit 1; fi exec "$@" lksctp-tools-1.0.16+dfsg.orig/src/withsctp/sctp_bind.c0000644000175000017500000000450612300634451022451 0ustar michaelmichael/* Wrap bind() to force the protocol for STREAM connections to SCTP. * * Thanks to Midgard Security Services for * http://www.securiteam.com/tools/3D5PTR5QAE.html * from whence I cribbed the code to find the old bind(). * * gcc sctp_socket.c sctp_bind.c -o sctp_socket.so -ldl -shared -O2 -s * export LD_PRELOAD=./sctp_socket.so * * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* for strncmp() */ #include #include "sctp_socket.h" /* IPPROTO_SCTP SHOULD be defined in * /usr/include/linux/in.h but probably isn't. * It is an enum element, not a #define, so we can't easily check. */ #define SHOULD_IPPROTO_SCTP 132 int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen) { _sctp_load_libs(); /* STUB. The intent is to allow us to substitute an elaborate call to * bindx() for the initial call to bind(). TBD. */ return (real_bind)(sockfd, my_addr, addrlen); } lksctp-tools-1.0.16+dfsg.orig/src/withsctp/README0000644000175000017500000000102212300634451021206 0ustar michaelmichaelThis is a package to let you use SCTP with your existing TCP-based binaries. usage: $ withsctp xinetd # Start xinetd stream services on SCTP. $ withsctp telnet localhost # Make a telnet over SCTP/IP connection. To install, edit the top of Makefile to set your install path(s) and then $ make all # make install This package originally written by La Monte H.P. Yarroll . To submit fixes or bug reports see lksctp.sourceforget.net. You can try the author or lksctp-developers@lists.sourceforget.net for support. lksctp-tools-1.0.16+dfsg.orig/src/withsctp/sctp_load_libs.c0000644000175000017500000000476012300634451023467 0ustar michaelmichael/* Load the real underlying functions for withsctp and related scripts. * * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "sctp_socket.h" int (*real_bind)(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen); int (*real_socket)(int domain, int type, int protocol); int (*real_setsockopt)(int s, int level, int optname, const void *optval, socklen_t optlen); static void *lib_handle = NULL; void _sctp_load_libs(void) { if (NULL != lib_handle) return; /* Only init once. */ if (!(lib_handle = dlopen("libc.so", RTLD_LAZY))) { if (!(lib_handle = dlopen("libc.so.6", RTLD_LAZY))) { fprintf(stderr, "error loading libc!\n"); exit (1); } } if (!(real_socket = dlsym(lib_handle, "socket"))) { fprintf(stderr, "socket() not found in libc!\n"); exit (1); } if (!(real_bind = dlsym(lib_handle, "bind"))) { fprintf(stderr, "bind() not found in libc!\n"); exit (1); } if (!(real_setsockopt = dlsym(lib_handle, "setsockopt"))) { fprintf(stderr, "setsockopt() not found in libc!\n"); exit (1); } } lksctp-tools-1.0.16+dfsg.orig/src/withsctp/sctp_socket.h0000644000175000017500000000662512300634451023036 0ustar michaelmichael/* Preprocessor definitions for withsctp and supporting scripts. * * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* for dlopen() and company */ #include #include #include #include #include extern int (*real_bind)(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen); extern int (*real_socket)(int domain, int type, int protocol); extern int (*real_setsockopt)(int s, int level, int optname, const void *optval, socklen_t optlen); extern void _sctp_load_libs(void); lksctp-tools-1.0.16+dfsg.orig/src/withsctp/sctp_sockopt.c0000644000175000017500000000435012300634451023214 0ustar michaelmichael/* Wrap socket() to force the protocol to SCTP for STREAM connections. * * Thanks to Midgard Security Services for * http://www.securiteam.com/tools/3D5PTR5QAE.html * from whence I cribbed the code to find the old socket(). * * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* for strncmp() */ #include #include "sctp_socket.h" /* IPPROTO_SCTP SHOULD be defined in * /usr/include/linux/in.h but probably isn't. * It is an enum element, not a #define, so we can't easily check. */ #define SHOULD_IPPROTO_SCTP 132 int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { _sctp_load_libs(); if ((IPPROTO_TCP == level) && (TCP_NODELAY == optname)) { level = SHOULD_IPPROTO_SCTP; optname = SCTP_NODELAY; } return (real_setsockopt)(s, level, optname, optval, optlen); } lksctp-tools-1.0.16+dfsg.orig/src/withsctp/checksctp.c0000644000175000017500000000372212300634451022452 0ustar michaelmichael/* Does this host have SCTP? * * Copyright 2003 La Monte HP Yarroll * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include /* IPPROTO_SCTP SHOULD be defined in * /usr/include/linux/in.h but probably isn't. * It is an enum element, not a #define, so we can't easily check. */ #define SHOULD_IPPROTO_SCTP 132 main() { int fd; fd = socket(PF_INET, SOCK_STREAM, SHOULD_IPPROTO_SCTP); if (fd <= 0) { perror("checksctp"); exit(1); } else { fprintf(stderr, "SCTP supported\n"); } close(fd); exit(0); } lksctp-tools-1.0.16+dfsg.orig/src/withsctp/Makefile.am0000644000175000017500000000124112300634451022365 0ustar michaelmichael# -*- Makefile -*- # # The author (La Monte H.P. Yarroll) disclaims copyright on this file. # include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.dirs include $(top_srcdir)/Makefile.rules bin_PROGRAMS = checksctp bin_SCRIPTS = withsctp AM_CPPFLAGS=-I$(top_srcdir)/src/include pkglib_LTLIBRARIES = libwithsctp.la libwithsctp_la_SOURCES = sctp_load_libs.c sctp_socket.c sctp_bind.c \ sctp_sockopt.c sctp_socket.h libwithsctp_la_LDFLAGS = -version-info 1:16:0 -ldl pkgdoc_DATA = sctp_load_libs.c sctp_socket.c sctp_bind.c \ sctp_sockopt.c sctp_socket.h checksctp.c withsctp: withsctp.in $(edit) $< >$@ EXTRA_DIST += withsctp.in CLEANFILES += withsctp lksctp-tools-1.0.16+dfsg.orig/src/withsctp/notes.txt0000644000175000017500000000027312300634451022226 0ustar michaelmichaelFri Dec 26 16:20:36 EST 2003 It would be nice for withsctp to provide more facilities. Perhaps we could capture the bind call and allow substitution such as the arguments to sctp_darn. lksctp-tools-1.0.16+dfsg.orig/src/apps/0000755000175000017500000000000012300634451017431 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/apps/nagle_snd.c0000644000175000017500000002764312300634451021543 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2002, 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 * * 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: * Ardelle Fan * Sridhar Samudrala */ /* This is a receiver for the performance test to verify Nagle's algorithm. * It creates a socket, binds to a address specified as a parameter and * sends 1,000,000 packets to a specified target. */ #include #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; void usage(char *argv0) { fprintf(stderr, "Usage: %s -H localhost [-P localport] " "-h remotehost [-p remoteport]\n" "\t\t[-S msgsize] [-I interval] -N\n" " -H, --local\t\tspecify one of the local addresses,\n" " -P, --local-port\tspecify the port number for local addresses,\n" " -h, --remote\t\tspecify one of the remote addresses,\n" " -p, --remote-port\tspecify the port number for remote addresses,\n" " -S, --size\t\tspecify the size(byte) of the sending message,\n" " -I, --interval\t\tspecify the interval(second) that sending messages at,\n" " -N, --nodelay\t\tspecify whether the SCTP allows Nagle's algorithm\n", argv0); } int main(int argc, char *argv[]) { int sk, i; struct hostent *hst, *tgt; sockaddr_storage_t host, target; sockaddr_storage_t msgname; 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; char *message; int error, pf_class; sctp_assoc_t associd; uint32_t ppid; uint32_t stream; char *remote_host = NULL; int remote_port = SCTP_TESTPORT_1; char *local_host = NULL; int local_port = SCTP_TESTPORT_2; int size = 1; int interval = 0; int nodelay = 0; int option_index = 0; char *big_buffer; int c; static struct option long_options[] = { {"local", 1, 0, 1}, {"local-port", 1, 0, 2}, {"remote", 1, 0, 3}, {"remote-port", 1, 0, 4}, {"size", 1, 0, 5}, {"interval", 1, 0, 6}, {"nodelay", 0, 0, 10}, {0, 0, 0, 0} }; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Parse the arguments. */ while (1) { c = getopt_long (argc, argv, "H:P:h:p:S:I:N", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); break; case 1: /* local host */ case 'H': local_host = optarg; break; case 2: /* local port */ case 'P': local_port = atoi(optarg); break; case 3: /* remote host */ case 'h': remote_host = optarg; break; case 4: /* remote port */ case 'p': remote_port = atoi(optarg); break; case 5: /* size */ case 'S': size = atoi(optarg); break; case 6: /* interval */ case 'I': interval = atoi(optarg); break; case 10: /* nodelay */ case 'N': nodelay = 1; break; case '?': usage(argv[0]); exit(0); default: printf ("%s: unrecognized option 0%c\n", argv[0], c); usage(argv[0]); exit(1); } } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf (stderr, "\n"); usage(argv[0]); exit(1); } if (!local_host || !remote_host) { fprintf(stderr, "%s: : option --local and --remote are required\n", argv[0]); usage(argv[0]); exit(1); } /* Set some basic values which depend on the address family. */ #if TEST_V6 hst = gethostbyname2(local_host, AF_INET6); if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv[0], local_host); exit(1); } host.v6.sin6_family = AF_INET6; memcpy(&host.v6.sin_addr, hst->h_addr_list[0], hst->h_length); host.v6.sin6_port = htons(local_port); tgt = gethostbyname2(remote_host, AF_INET6); if (tgt == NULL || tgt->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv[0], remote_host); exit(1); } target.v6.sin6_family = AF_INET6; memcpy(&target.v6.sin_addr, tgt->h_addr_list[0], tgt->h_length); target.v6.sin6_port = htons(remote_port); pf_class = PF_INET6; #else hst = gethostbyname(local_host); if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv[0], local_host); exit(1); } host.v4.sin_family = AF_INET; memcpy(&host.v4.sin_addr, hst->h_addr_list[0], hst->h_length); host.v4.sin_port = htons(local_port); tgt = gethostbyname(remote_host); if (tgt == NULL || tgt->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv[0], remote_host); exit(1); } target.v4.sin_family = AF_INET; memcpy(&target.v4.sin_addr, tgt->h_addr_list[0], tgt->h_length); target.v4.sin_port = htons(remote_port); pf_class = PF_INET; #endif /* TEST_V6 */ sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(sk); test_setsockopt(sk, SCTP_NODELAY, &nodelay, sizeof(int)); /* Bind the sockets to the test port. */ test_bind(sk, &host.sa, sizeof(host)); /* Mark sk as being able to accept new associations. */ test_listen(sk, 1); /* Build up a msghdr structure we can use for all sending. */ outmessage.msg_name = ⌖ outmessage.msg_namelen = sizeof(target); 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; message = test_malloc((size + 1) * sizeof(u_int8_t)); for(i=0; i + 10 < size; i+= 10) strncpy(message+i, "1234567890", 10); strncpy(message+i, "1234567890", size-i); *(message+size) = 0; outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = size + 1; printf("Initiating connection with %s:%d...\n", remote_host, remote_port); /* Send the first message. This will create the association. */ test_sendmsg(sk, &outmessage, 0, size+1); memset(&inmessage, 0, sizeof(inmessage)); big_buffer = test_malloc(REALLY_BIG); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof(msgname); memset(&msgname, 0, sizeof(msgname)); /* Get the communication up message on sk. */ error = test_recvmsg(sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); associd = ((struct sctp_assoc_change *)iov.iov_base)->sac_assoc_id; printf("Established connection with "); if (AF_INET == msgname.sa.sa_family) printf("%d.%d.%d.%d(%d)\n", NIPQUAD(msgname.v4.sin_addr), ntohs(msgname.v4.sin_port)); if (AF_INET6 == msgname.sa.sa_family) printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)\n", NIP6(msgname.v6.sin6_addr), ntohs(msgname.v6.sin6_port)); printf("Sending data to receiver...\n"); for (i=1; i<1000000; i++) { if (interval) sleep(interval); outmessage.msg_name = ⌖ outmessage.msg_namelen = sizeof(target); outmessage.msg_iov = &out_iov; outmessage.msg_iovlen = 1; 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++; sinfo->sinfo_ppid = ppid; sinfo->sinfo_stream = stream; sinfo->sinfo_assoc_id = associd; outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = size + 1; test_sendmsg(sk, &outmessage, 0, size+1); } printf("\n\n\t\tComplete all the data sendings to receiver...\n\n\n"); error = 0; close(sk); free(message); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/apps/nagle_rcv.c0000644000175000017500000001710212300634451021536 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2002, 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 * * 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: * Ardelle Fan * Sridhar Samudrala */ /* This is a receiver for the performance test to verify Nagle's algorithm. * It creates a socket, binds to a address specified as a parameter and * goes into a receive loop waiting for 1,000,000 packets. Then it calculates * the packet receive rate, i.e. packets/second. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; void usage(char *progname) { fprintf(stderr, "Usage: %s -H hostname [-P port]\n", progname); fprintf(stderr, " -H, --local\t\t local hostname,\n"); fprintf(stderr, " -P, --local-port\t local port,\n"); } int main(int argc, char *argv[]) { int sk, i; struct hostent *hst; sockaddr_storage_t host; sockaddr_storage_t msgname; struct iovec iov; struct msghdr inmessage; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; int error, pf_class; char *big_buffer; char *local_host = NULL; int local_port = SCTP_TESTPORT_1; int option_index = 0; time_t from, to; int bytes_received = 0; int c; static struct option long_options[] = { {"local", 1, 0, 1}, {"local-port", 1, 0, 2}, {0, 0, 0, 0} }; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Parse the arguments. */ while (1) { c = getopt_long (argc, argv, "H:P:", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); break; case 1: /* local host */ case 'H': local_host = optarg; break; case 2: /* local port */ case 'P': local_port = atoi(optarg); break; case '?': usage(argv[0]); exit(0); default: printf ("%s: unrecognized option 0%c\n", argv[0], c); usage(argv[0]); exit(1); } } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf (stderr, "\n"); usage(argv[0]); exit(1); } if (!local_host) { fprintf(stderr, "%s: : option -H, --local is required\n", argv[0]); usage(argv[0]); exit(1); } /* Set some basic values which depend on the address family. */ #if TEST_V6 hst = gethostbyname2(local_host, AF_INET6); if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv[0], local_host); exit(1); } pf_class = PF_INET6; host.v6.sin6_family = AF_INET6; memcpy(&host.v6.sin_addr, hst->h_addr_list[0], hst->h_length); host.v6.sin6_port = htons(local_port); #else hst = gethostbyname(local_host); if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv[0], local_host); exit(1); } pf_class = PF_INET; host.v4.sin_family = AF_INET; memcpy(&host.v4.sin_addr, hst->h_addr_list[0], hst->h_length); host.v4.sin_port = htons(local_port); #endif /* TEST_V6 */ /* Create the endpoint which will talk to nagle_snd. */ sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(sk); /* Bind the sockets to the test port. */ test_bind(sk, &host.sa, sizeof(host)); /* Mark sk as being able to accept new associations. */ test_listen(sk, 1); printf("Listening on port:%d\n", local_port); /* Initialize inmessage for receives. */ memset(&inmessage, 0, sizeof(inmessage)); big_buffer = test_malloc(REALLY_BIG); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof(msgname); memset(&msgname, 0, sizeof(msgname)); /* Get the communication up message on sk. */ error = test_recvmsg(sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); printf("Established connection with "); if (AF_INET == msgname.sa.sa_family) printf("%d.%d.%d.%d(%d)\n", NIPQUAD(msgname.v4.sin_addr), ntohs(msgname.v4.sin_port)); if (AF_INET6 == msgname.sa.sa_family) printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x(%d)\n", NIP6(msgname.v6.sin6_addr), ntohs(msgname.v6.sin6_port)); time(&from); for (i=0; i<1000000; i++) { inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_namelen = sizeof(msgname); error = test_recvmsg(sk, &inmessage, MSG_WAITALL); if (inmessage.msg_flags & MSG_NOTIFICATION) break; printf("Received %d bytes of data\n", error); bytes_received += error; } time(&to); printf("\t%d messages(%d bytes) successfully received in %ld " "seconds.\n", i, bytes_received, to - from); printf("The receive rate is %ld bytes/second\n", bytes_received/(to - from)); /* Shut down the link. */ error = 0; close(sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/apps/peel_server.c0000644000175000017500000004547012300634451022122 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2003 * Copyright (c) 2003 Cisco * * 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. * * In addition: * * Copyright (c) 2003 Cisco * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * c) Neither the name of Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers * * 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: * Randall Stewart * Sridhar Samudrala */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __NetBSD__ #include #endif #define SCTP_CRC32C_POLY 0x1EDC6F41 #define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF]) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copyright 2001, D. Otis. Use this program, code or tables */ /* extracted from it, as desired without restriction. */ /* */ /* 32 Bit Reflected CRC table generation for SCTP. */ /* To accommodate serial byte data being shifted out least */ /* significant bit first, the table's 32 bit words are reflected */ /* which flips both byte and bit MS and LS positions. The CRC */ /* is calculated MS bits first from the perspective of the serial*/ /* stream. The x^32 term is implied and the x^0 term may also */ /* be shown as +1. The polynomial code used is 0x1EDC6F41. */ /* Castagnoli93 */ /* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ /* x^11+x^10+x^9+x^8+x^6+x^0 */ /* Guy Castagnoli Stefan Braeuer and Martin Herrman */ /* "Optimization of Cyclic Redundancy-Check Codes */ /* with 24 and 32 Parity Bits", */ /* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static unsigned char buffer1[4100]; static unsigned char buffer2[4100]; static unsigned char buffer3[4100]; static unsigned char buffer4[4100]; static struct sockaddr_in bindto,got; static socklen_t len; unsigned long sctp_crc_c[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, }; u_int32_t update_crc32(u_int32_t crc32, unsigned char *buffer, unsigned int length) { int i; for (i = 0; i < length; i++) { SCTP_CRC32C(crc32, buffer[i]); } return (crc32); } u_int32_t sctp_csum_finalize(u_int32_t crc32) { u_int32_t result; #if BYTE_ORDER == BIG_ENDIAN u_int8_t byte0, byte1, byte2, byte3; #endif /* Complement the result */ result = ~crc32; #if BYTE_ORDER == BIG_ENDIAN /* * For BIG-ENDIAN.. aka Motorola byte order the result is in * little-endian form. So we must manually swap the bytes. Then * we can call htonl() which does nothing... */ byte0 = result & 0x000000ff; byte1 = (result >> 8) & 0x000000ff; byte2 = (result >> 16) & 0x000000ff; byte3 = (result >> 24) & 0x000000ff; result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); crc32 = htonl(result); #else /* * For INTEL platforms the result comes out in network order. * No htonl is required or the swap above. So we optimize out * both the htonl and the manual swap above. */ crc32 = result; #endif return (crc32); } int check_buffers(void) { /* Prepare buffers */ u_int32_t temp,*csum; int ret=0; temp = 0xffffffff; temp = update_crc32(temp,buffer1,(sizeof(buffer1)-4)); temp = sctp_csum_finalize(temp); csum = (u_int32_t *)(buffer1+(sizeof(buffer1)-4)); if(*csum != temp){ printf("Buffer1: Found csum:%x calculated:%x\n", *csum,temp); ret++; } temp = 0xffffffff; temp = update_crc32(temp,buffer2,(sizeof(buffer2)-4)); temp = sctp_csum_finalize(temp); csum = (u_int32_t *)(buffer2+(sizeof(buffer2)-4)); if(*csum != temp){ printf("Buffer2: Found csum:%x calculated:%x\n", *csum,temp); ret++; } temp = 0xffffffff; temp = update_crc32(temp,buffer3,(sizeof(buffer3)-4)); temp = sctp_csum_finalize(temp); csum = (u_int32_t *)(buffer3+(sizeof(buffer3)-4)); if(*csum != temp){ printf("Buffer3: Found csum:%x calculated:%x\n", *csum,temp); ret++; } temp = 0xffffffff; temp = update_crc32(temp,buffer4,(sizeof(buffer4)-4)); temp = sctp_csum_finalize(temp); csum = (u_int32_t *)(buffer4+(sizeof(buffer4)-4)); if(*csum != temp){ printf("Buffer4: Found csum:%x calculated:%x\n", *csum,temp); ret++; } return(ret); } static int my_handle_notification(int fd,char *notify_buf) { union sctp_notification *snp; struct sctp_assoc_change *sac; struct sctp_paddr_change *spc; struct sctp_remote_error *sre; struct sctp_send_failed *ssf; struct sctp_shutdown_event *sse; int asocUp; char *str; char buf[256]; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; snp = (union sctp_notification *)notify_buf; asocUp = 0; switch(snp->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: sac = &snp->sn_assoc_change; switch(sac->sac_state) { case SCTP_COMM_UP: str = "COMMUNICATION UP"; asocUp++; break; case SCTP_COMM_LOST: str = "COMMUNICATION LOST"; break; case SCTP_RESTART: str = "RESTART"; asocUp++; break; case SCTP_SHUTDOWN_COMP: str = "SHUTDOWN COMPLETE"; break; case SCTP_CANT_STR_ASSOC: str = "CANT START ASSOC"; printf("EXIT:SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str, (uint32_t)sac->sac_assoc_id); exit(0); break; default: str = "UNKNOWN"; } /* end switch(sac->sac_state) */ printf("SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str, (uint32_t)sac->sac_assoc_id); break; case SCTP_PEER_ADDR_CHANGE: spc = &snp->sn_paddr_change; switch(spc->spc_state) { case SCTP_ADDR_AVAILABLE: str = "ADDRESS AVAILABLE"; break; case SCTP_ADDR_UNREACHABLE: str = "ADDRESS UNAVAILABLE"; break; case SCTP_ADDR_REMOVED: str = "ADDRESS REMOVED"; break; case SCTP_ADDR_ADDED: str = "ADDRESS ADDED"; break; case SCTP_ADDR_MADE_PRIM: str = "ADDRESS MADE PRIMARY"; break; default: str = "UNKNOWN"; } /* end switch */ sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; if (sin6->sin6_family == AF_INET6) { inet_ntop(AF_INET6, (char*)&sin6->sin6_addr, buf, sizeof(buf)); } else { sin = (struct sockaddr_in *)&spc->spc_aaddr; inet_ntop(AF_INET, (char*)&sin->sin_addr, buf, sizeof(buf)); } printf("SCTP_PEER_ADDR_CHANGE: %s, addr=%s, assoc=%xh\n", str, buf, (uint32_t)spc->spc_assoc_id); break; case SCTP_REMOTE_ERROR: sre = &snp->sn_remote_error; printf("SCTP_REMOTE_ERROR: assoc=%xh\n", (uint32_t)sre->sre_assoc_id); break; case SCTP_SEND_FAILED: ssf = &snp->sn_send_failed; printf("SCTP_SEND_FAILED: assoc=%xh\n", (uint32_t)ssf->ssf_assoc_id); break; case SCTP_ADAPTATION_INDICATION: { struct sctp_adaptation_event *ae; ae = &snp->sn_adaptation_event; printf("\nSCTP_adaptation_indication bits:0x%x\n", (u_int)ae->sai_adaptation_ind); } break; case SCTP_PARTIAL_DELIVERY_EVENT: { struct sctp_pdapi_event *pdapi; pdapi = &snp->sn_pdapi_event; printf("SCTP_PD-API event:%u\n", pdapi->pdapi_indication); if(pdapi->pdapi_indication == 0){ printf("PDI- Aborted\n"); } } break; case SCTP_SHUTDOWN_EVENT: sse = &snp->sn_shutdown_event; printf("SCTP_SHUTDOWN_EVENT: assoc=%xh\n", (uint32_t)sse->sse_assoc_id); break; default: printf("Unknown notification event type=%xh\n", snp->sn_header.sn_type); } /* end switch(snp->sn_type) */ return(asocUp); } static char readBuffer[65535]; static int sz=0; static char controlVector[65535]; static struct msghdr msg; int my_sctpReadInput(int fd,int maxread) { /* receive some number of datagrams and * act on them. */ struct iovec iov[2]; unsigned char from[200]; memset(&msg,0,sizeof(msg)); memset(controlVector,0,sizeof(controlVector)); memset(readBuffer,0,sizeof(readBuffer)); iov[0].iov_base = readBuffer; iov[0].iov_len = maxread; iov[1].iov_base = NULL; iov[1].iov_len = 0; msg.msg_name = (caddr_t)from; msg.msg_namelen = sizeof(from); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)controlVector; msg.msg_controllen = sizeof(controlVector); errno = 0; sz = recvmsg(fd,&msg,0); printf("Read fd:%d returns %d errno:%d control len is %zu msgflg:%x\n", fd, sz,errno, msg.msg_controllen, msg.msg_flags); if (msg.msg_flags & MSG_NOTIFICATION) { printf("Got a notification\n"); return(my_handle_notification(fd,readBuffer)); }else{ printf("Got data\n"); return(-1); } } int poll_fd(int fd) { int cameup; int max; fd_set readfds,writefds,exceptfds; struct timeval tv; memset(&tv,0,sizeof(tv)); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); cameup = 0; max = fd + 1; printf("poll_fd\n"); FD_SET(fd,&readfds); select(max,&readfds,&writefds,&exceptfds,NULL); if(FD_ISSET(fd,&readfds)){ printf("Read please\n"); cameup += my_sctpReadInput(fd,4100); } return(cameup); } static sctp_assoc_t dig_out_asocid(void) { struct sctp_sndrcvinfo *s_info; struct cmsghdr *cmsg; s_info = NULL; if(msg.msg_controllen){ /* parse through and see if we find * the sctp_sndrcvinfo */ cmsg = (struct cmsghdr *)controlVector; while(cmsg){ if(cmsg->cmsg_level == IPPROTO_SCTP){ if(cmsg->cmsg_type == SCTP_SNDRCV){ /* Got it */ s_info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); break; } } cmsg = CMSG_NXTHDR(&msg,cmsg); } }else{ printf("No CMSG?\n"); exit(0); } if(s_info == NULL){ printf("No sinfo?\n"); exit(0); } return(s_info->sinfo_assoc_id); } void process(int fd,int magic) { int fd1,num_asoc,ret,i; sctp_assoc_t asoc; struct timespec ts; num_asoc = 0; i = 1; ts.tv_sec = 0; ts.tv_nsec = 10000; while(i < 4099){ printf("pass %d\n",i); while(num_asoc < 2){ ret = poll_fd(fd); if(ret >0 ){ num_asoc += ret; }else if(ret == 0){ sleep(1); }else if(ret < 0){ printf("Got data? %d\n",sz); sleep(1); } printf("asoc count is %d\n",num_asoc); } again: printf("Reading for %d bytes from fd:%d\n", i,fd); my_sctpReadInput(fd,i); if(sz == i){ memcpy(buffer1,readBuffer,i); }else{ printf("Huh I am messed up read %d wanted %d\n", sz,i); goto again; } if(msg.msg_flags & MSG_EOR){ printf("Huh got EOR on paritial read?\n"); exit(0); } asoc = dig_out_asocid(); nanosleep(&ts,NULL); fd1 = sctp_peeloff(fd,asoc); if(fd1 == -1){ printf("peeloff failed %d/err:%d\n", fd1,errno); exit(0); } my_sctpReadInput(fd1,(4100-i)); if(sz > 0){ memcpy(&buffer1[i],readBuffer,sz); printf("Copied %d bytes\n",sz); }else{ printf("Huh only read %d\n",sz); } if(magic >= i){ printf("magic engaged\n"); my_sctpReadInput(fd,i); }else{ my_sctpReadInput(fd,4100); } if(sz > 0){ memcpy(buffer2,readBuffer,sz); printf("copied %d bytes\n",sz); }else{ printf("Huh only read %d\n",sz); } my_sctpReadInput(fd1,4100); if(sz > 0){ memcpy(buffer3,readBuffer,sz); printf("copied %d bytes\n",sz); }else{ printf("Huh only read %d\n",sz); } my_sctpReadInput(fd,4100); if(sz > 0){ memcpy(buffer4,readBuffer,sz); printf("copied %d bytes\n",sz); }else{ printf("Huh only read %d\n",sz); } if(check_buffers()){ exit(0); } close(fd1); i++; num_asoc--; } } int main(int argc, char **argv) { int i,fd; uint16_t myport=0; int magic=0; struct sctp_event_subscribe event; while((i= getopt(argc,argv,"m:M:")) != EOF){ switch(i){ case 'm': myport = (uint16_t)strtol(optarg,NULL,0); break; case 'M': magic = strtol(optarg,NULL,0); break; }; } /**********************socket 1 *******************/ fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if(fd == -1){ printf("can't open socket:%d\n",errno); return(-1); } memset(&bindto,0,sizeof(bindto)); //len = bindto.sin_len = sizeof(bindto); len = sizeof(bindto); bindto.sin_family = AF_INET; printf("bind port %d\n",myport); bindto.sin_port = htons(myport); if(bind(fd,(struct sockaddr *)&bindto, len) < 0){ printf("can't bind a socket:%d\n",errno); close(fd); return(-1); } if(getsockname(fd,(struct sockaddr *)&got,&len) < 0){ printf("get sockname failed err:%d\n",errno); close(fd); return(-1); } printf("fd uses port %d\n",ntohs(got.sin_port)); listen(fd,100); /* enable all event notifications */ event.sctp_data_io_event = 1; event.sctp_association_event = 1; event.sctp_address_event = 1; event.sctp_send_failure_event = 1; event.sctp_peer_error_event = 1; event.sctp_shutdown_event = 1; event.sctp_partial_delivery_event = 1; event.sctp_adaptation_layer_event = 1; if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) { printf("Gak, can't set events errno:%d\n",errno); exit(0); } printf("to process\n"); process(fd,magic); return(0); } lksctp-tools-1.0.16+dfsg.orig/src/apps/sctp_test.c0000644000175000017500000012531712300634451021616 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999 Cisco * Copyright (c) 1999, 2000, 2001 Motorola * Copyright (c) 2001-2002 Nokia * Copyright (c) 2001 La Monte H.P. Yarroll * * This is a userspace test application for the SCTP kernel * implementation. * * This program 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. * * This program 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Written or modified by: * Hui Huang * Sridhar Samudrala * Jon Grimm * Daisy Chang * Ryan Layer */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define REALLY_BIG 65536 #define SERVER 0 #define CLIENT 1 #define MIXED 2 #define NOT_DEFINED 666 #define REPEAT 10 #define BIG_REPEAT 1000000 #define MAX_BIND_RETRYS 10 #define BODYSIZE 10 #define MSG_CNT 10 /* If this is changed the msg_sizes array needs to be modified accordingly. */ #define DEFAULT_MAX_WINDOW 32768 #define DEFAULT_MIN_WINDOW 1500 #define DEBUG_NONE 0 #define DEBUG_MIN 1 #define DEBUG_MAX 2 #define STREAM_PATTERN_SEQUENTIAL 0 #define STREAM_PATTERN_RANDOM 1 #define ORDER_PATTERN_UNORDERED 0 #define ORDER_PATTERN_ORDERED 1 #define ORDER_PATTERN_ALTERNATE 2 #define ORDER_PATTERN_RANDOM 3 #define ASSOC_PATTERN_SEQUENTIAL 0 #define ASSOC_PATTERN_RANDOM 1 #define NCASES 6 #define MAX_POLL_SKS 256 #define DEBUG_PRINT(level, print_this...) \ { \ if (debug_level >= level) { \ fprintf(stdout, print_this); \ fflush(stdout); \ } \ } /* DEBUG_PRINT */ /* Convenience structure to determine space needed for cmsg. */ typedef union { struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcvinfo; } _sctp_cmsg_data_t; #ifdef __FreeBSD__ typedef union { int raw; struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcv; } sctp_cmsg_data_t; #endif #define CMSG_SPACE_INITMSG (CMSG_SPACE(sizeof(struct sctp_initmsg))) #define CMSG_SPACE_SNDRCV (CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))) typedef struct { int rem_port; int order_state; int stream_state; int msg_cnt; int msg_sent; int cycle; } _assoc_state; typedef struct { int sk; int assoc_i; _assoc_state *assoc_state; } _poll_sks; char *local_host = NULL; int local_port = 0; char *remote_host = NULL; int remote_port = 0; /* struct sockaddr_in s_rem, s_loc; */ struct sockaddr_storage s_rem, s_loc; int r_len, l_len; int test_case = 0; int size_arg = 0; int xflag = 0; int debug_level = DEBUG_MAX; int do_exit = 1; int stream_pattern = STREAM_PATTERN_SEQUENTIAL; int stream_state = 0; int order_pattern = ORDER_PATTERN_UNORDERED; int order_state = 0; int max_stream = 0; int seed = 0; int max_msgsize = DEFAULT_MAX_WINDOW; int timetolive = 0; int assoc_pattern = ASSOC_PATTERN_SEQUENTIAL; int socket_type = SOCK_SEQPACKET; int repeat_count = 0; int listeners = 0; int tosend = 0; _poll_sks poll_sks[MAX_POLL_SKS]; int repeat = REPEAT; int msg_cnt = MSG_CNT; int drain = 0; int role = NOT_DEFINED; struct sockaddr *bindx_add_addrs = NULL; int bindx_add_count = 0; struct sockaddr *connectx_addrs = NULL; int connectx_count = 0; int if_index = 0; unsigned char msg[] = "012345678901234567890123456789012345678901234567890"; static int msg_sizes[NCASES][MSG_CNT] = {{1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1452, 2904, 4356, 1452, 2904, 4356, 1452, 2904, 4356, 1452}, {1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453, 1453}, {1, 1453, 32768, 1, 1453, 32768, 1, 1453, 32768, 1}, {1, 1000, 2000, 3000, 5000, 10000, 15000, 20000, 25000, 32768}, {32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768, 32768}, }; static const char *sac_state_tbl[] = { "COMMUNICATION_UP", "COMMUNICATION_LOST", "RESTART", "SHUTDOWN_COMPLETE", "CANT_START_ASSOCICATION" }; void usage(char *argv0) { fprintf(stderr, "\nusage:\n"); fprintf(stderr, " server:\n"); fprintf(stderr, " %8s -H local-addr -P local-port -l [-d level] [-x]\n" "\t [-L num-ports] [-S num-ports]\n" "\t [-a assoc-pattern]\n" "\t [-i interface]\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, " client:\n"); fprintf(stderr, " %8s -H local-addr -P local-port -h remote-addr\n" "\t -p remote-port -s [-c case ] [-d level]\n" "\t [-x repeat] [-o order-pattern] ream-pattern]\n" "\t [-M max-stream] [-r rand-seed]\n" "\t [-m max-msgsize]\n" "\t [-L num-ports] [-S num-ports]\n" "\t [-a assoc-pattern]\n" "\t [-i interface]\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, "\t-a assoc_pattern in the mixed mode\n"); fprintf(stderr, "\t 0 = sequential ascending(default)\n"); fprintf(stderr, "\t 1 = random\n"); fprintf(stderr, "\t-d debug\n"); fprintf(stderr, "\t 0 = none\n"); fprintf(stderr, "\t 1 = min(default)\n"); fprintf(stderr, "\t 2 = max\n"); fprintf(stderr, "\t-c testcase\n"); fprintf(stderr, "\t 0 = 1 byte packets.\n"); fprintf(stderr, "\t 1 = 1452 byte packets.\n"); fprintf(stderr, "\t (fragmentation point for an i/f with "); fprintf(stderr, "1500 as mtu.)\n"); fprintf(stderr, "\t 2 = 1453 byte packets.\n"); fprintf(stderr, "\t (min. size at which fragmentation occurs\n"); fprintf(stderr, "\t for an i/f with 1500 as mtu.)\n"); fprintf(stderr, "\t 3 = Sequence of 1, 1453, 32768 byte packets.\n"); fprintf(stderr, "\t 4 = Sequence of following size packets.\n"); fprintf(stderr, "\t (1, 1000, 2000, 3000, 5000, 10000,"); fprintf(stderr, "15000, 20000, 25000, 32768)\n"); fprintf(stderr, "\t 5 = 32768 byte packets.\n"); fprintf(stderr, "\t (default max receive window size.)\n"); fprintf(stderr, "\t 6 = random size packets.\n"); fprintf(stderr, "\t -ve value = Packets of specifed size.\n"); fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n"); fprintf(stderr, "\t-x number of repeats\n"); fprintf(stderr, "\t-o order-pattern\n"); fprintf(stderr, "\t 0 = all unordered(default) \n"); fprintf(stderr, "\t 1 = all ordered \n"); fprintf(stderr, "\t 2 = alternating \n"); fprintf(stderr, "\t 3 = random\n"); fprintf(stderr, "\t-t stream-pattern\n"); fprintf(stderr, "\t 0 = sequential ascending(default)\n"); fprintf(stderr, "\t 1 = random\n"); fprintf(stderr, "\t-M max-stream (default value 0)\n"); fprintf(stderr, "\t-r seed (default 0, use time())\n"); fprintf(stderr, "\t-L num-ports (default value 0). Run the mixed mode\n"); fprintf(stderr, "\t-S num-ports (default value 0). Run the mixed mode\n"); fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n"); fprintf(stderr, "\t-T use SOCK_STREAM tcp-style sockets.\n"); fprintf(stderr, "\t-B add the specified address(es) as additional bind\n"); fprintf(stderr, "\t addresses of the local socket. Multiple addresses can\n"); fprintf(stderr, "\t be specified by using this argument multiple times.\n"); fprintf(stderr, "\t For example, '-B 10.0.0.1 -B 20.0.0.2'.\n"); fprintf(stderr, "\t-C use the specified address(es) for connection to the\n"); fprintf(stderr, "\t peer socket. Multiple addresses can be specified by\n"); fprintf(stderr, "\t using this argument multiple times.\n"); fprintf(stderr, "\t For example, '-C 10.0.0.1 -C 20.0.0.2'.\n"); fprintf(stderr, "\t This option is incompatible with the -h option.\n"); fprintf(stderr, "\t-O time to live (default value 0)\n"); fprintf(stderr, "\n"); fflush(stderr); } /* usage() */ void * build_msg(int len) { int i = len - 1; int n; char *msg_buf, *p; msg_buf = malloc(len); if (NULL == msg_buf) { fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n"); exit(1); } p = msg_buf; do { n = ((i > 50)?50:i); memcpy(p, msg, ((i > 50)?50:i)); p += n; i -= n; } while (i > 0); msg_buf[len-1] = '\0'; return(msg_buf); } /* build_msg() */ static int print_cmsg(int type, sctp_cmsg_data_t *data) { switch(type) { case SCTP_INIT: DEBUG_PRINT(DEBUG_MAX, "\tINIT\n"); if (DEBUG_MAX == debug_level) { printf("\t\tsinit_num_ostreams=%d ", data->init.sinit_num_ostreams); printf("sinit_max_instreams=%d ", data->init.sinit_max_instreams); printf("sinit_max_attempts=%d ", data->init.sinit_max_attempts); printf("sinit_max_init_timeo=%d\n", data->init.sinit_max_init_timeo); } break; case SCTP_SNDRCV: DEBUG_PRINT(DEBUG_MAX, "\t SNDRCV"); if (DEBUG_MAX == debug_level) { printf("(stream=%u ", data->sndrcv.sinfo_stream); printf("ssn=%u ", data->sndrcv.sinfo_ssn); printf("tsn=%u ", data->sndrcv.sinfo_tsn); printf("flags=0x%x ", data->sndrcv.sinfo_flags); printf("ppid=%u\n", data->sndrcv.sinfo_ppid); printf("cumtsn=%u\n", data->sndrcv.sinfo_cumtsn); } break; default: DEBUG_PRINT(DEBUG_MIN, "\tUnknown type: %d\n", type); break; } fflush(stdout); return 0; } /* print_cmsg() */ /* This function prints the message. */ static int print_message(const int sk, struct msghdr *msg, size_t msg_len) { struct cmsghdr *scmsg; sctp_cmsg_data_t *data; int i; if (!(MSG_NOTIFICATION & msg->msg_flags)) { int index = 0; DEBUG_PRINT(DEBUG_MIN, "Data %zu bytes.", msg_len); DEBUG_PRINT(DEBUG_MAX, " First %zu bytes: ", (msg_len < BODYSIZE)?msg_len:BODYSIZE); /* Make sure that everything is printable and that we * are NUL terminated... */ while ( msg_len > 0 ) { char *text, tmptext[BODYSIZE]; int len; memset(tmptext, 0x0, BODYSIZE); text = msg->msg_iov[index].iov_base; len = msg->msg_iov[index].iov_len; if (msg_len == 1 && text[0] == 0) { DEBUG_PRINT(DEBUG_MIN, " text[0]=%d", text[0]); break; } if ( len > msg_len ) { /* text[(len = msg_len) - 1] = '\0'; */ text[(len = msg_len)] = '\0'; } if ( (msg_len -= len) > 0 ) { index++; } for (i = 0; i < len - 1; ++i) { if (!isprint(text[i])) text[i] = '.'; } strncpy(tmptext, text, BODYSIZE); tmptext[BODYSIZE-1] = '\0'; DEBUG_PRINT(DEBUG_MAX, "%s", tmptext); } DEBUG_PRINT(DEBUG_MIN, "\n"); fflush(stdout); } else { /* if(we have notification) */ struct sctp_assoc_change *sac; struct sctp_send_failed *ssf; struct sctp_paddr_change *spc; struct sctp_remote_error *sre; union sctp_notification *snp; char addrbuf[INET6_ADDRSTRLEN]; const char *ap; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; int index = 0; snp = (union sctp_notification *)msg->msg_iov[index].iov_base; DEBUG_PRINT(DEBUG_MIN, "Notification:"); switch (snp->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: sac = &snp->sn_assoc_change; DEBUG_PRINT(DEBUG_MIN, " SCTP_ASSOC_CHANGE(%s)\n", sac_state_tbl[sac->sac_state]); DEBUG_PRINT(DEBUG_MAX, "\t\t(assoc_change: state=%hu, " "error=%hu, instr=%hu " "outstr=%hu)\n", sac->sac_state, sac->sac_error, sac->sac_inbound_streams, sac->sac_outbound_streams); break; case SCTP_PEER_ADDR_CHANGE: spc = &snp->sn_paddr_change; DEBUG_PRINT(DEBUG_MIN, " SCTP_PEER_ADDR_CHANGE\n"); if (spc->spc_aaddr.ss_family == AF_INET) { sin = (struct sockaddr_in *) &spc->spc_aaddr; ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf, INET6_ADDRSTRLEN); } else { sin6 = (struct sockaddr_in6 *) &spc->spc_aaddr; ap = inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, INET6_ADDRSTRLEN); } DEBUG_PRINT(DEBUG_MAX, "\t\t(peer_addr_change: %s " "state=%d, error=%d)\n", ap, spc->spc_state, spc->spc_error); break; case SCTP_SEND_FAILED: ssf = &snp->sn_send_failed; DEBUG_PRINT(DEBUG_MIN, " SCTP_SEND_FAILED\n"); DEBUG_PRINT(DEBUG_MAX, "\t\t(sendfailed: len=%hu " "err=%d)\n", ssf->ssf_length, ssf->ssf_error); break; case SCTP_REMOTE_ERROR: sre = &snp->sn_remote_error; DEBUG_PRINT(DEBUG_MIN, " SCTP_REMOTE_ERROR\n"); DEBUG_PRINT(DEBUG_MAX, "\t\t(remote_error: err=%hu)\n", ntohs(sre->sre_error)); break; case SCTP_SHUTDOWN_EVENT: DEBUG_PRINT(DEBUG_MIN, " SCTP_SHUTDOWN_EVENT\n"); break; default: DEBUG_PRINT(DEBUG_MIN, " Unknown type: %hu\n", snp->sn_header.sn_type); break; } fflush(stdout); return 1; } /* notification received */ for (scmsg = CMSG_FIRSTHDR(msg); scmsg != NULL; scmsg = CMSG_NXTHDR(msg, scmsg)) { data = (sctp_cmsg_data_t *)CMSG_DATA(scmsg); if (debug_level) print_cmsg(scmsg->cmsg_type, data); } fflush(stdout); return 0; } /* print_message() */ struct sockaddr * append_addr(const char *parm, struct sockaddr *addrs, int *ret_count) { struct sockaddr *new_addrs = NULL; void *aptr; struct sockaddr *sa_addr; struct sockaddr_in *b4ap; struct sockaddr_in6 *b6ap; struct hostent *hst4 = NULL; struct hostent *hst6 = NULL; int i4 = 0; int i6 = 0; int j; int orig_count = *ret_count; int count = orig_count; /* Get the entries for this host. */ hst4 = gethostbyname(parm); hst6 = gethostbyname2(parm, AF_INET6); if ((NULL == hst4 || hst4->h_length < 1) && (NULL == hst6 || hst6->h_length < 1)) { fprintf(stderr, "bad hostname: %s\n", parm); goto finally; } /* Figure out the number of addresses. */ if (NULL != hst4) { for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) { count++; } } if (NULL != hst6) { for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) { count++; } } /* Expand memory for the new addresses. Assume all the addresses * are v6 addresses. */ new_addrs = (struct sockaddr *) realloc(addrs, sizeof(struct sockaddr_in6) * count); if (NULL == new_addrs) { count = *ret_count; goto finally; } /* Skip the existing addresses. */ aptr = new_addrs; for (j = 0; j < orig_count; j++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: aptr += sizeof(struct sockaddr_in); break; case AF_INET6: aptr += sizeof(struct sockaddr_in6); break; default: count = orig_count; goto finally; } } /* Put the new addresses away. */ if (NULL != hst4) { for (j = 0; j < i4; ++j) { b4ap = (struct sockaddr_in *)aptr; memset(b4ap, 0x00, sizeof(*b4ap)); b4ap->sin_family = AF_INET; b4ap->sin_port = htons(local_port); bcopy(hst4->h_addr_list[j], &b4ap->sin_addr, hst4->h_length); aptr += sizeof(struct sockaddr_in); } /* for (loop through the new v4 addresses) */ } if (NULL != hst6) { for (j = 0; j < i6; ++j) { b6ap = (struct sockaddr_in6 *)aptr; memset(b6ap, 0x00, sizeof(*b6ap)); b6ap->sin6_family = AF_INET6; b6ap->sin6_port = htons(local_port); b6ap->sin6_scope_id = if_index; bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr, hst6->h_length); aptr += sizeof(struct sockaddr_in6); } /* for (loop through the new v6 addresses) */ } finally: *ret_count = count; return new_addrs; } /* append_addr() */ int socket_r(void) { struct sctp_event_subscribe subscribe; int sk, error; DEBUG_PRINT(DEBUG_MIN, "\tsocket(%s, IPPROTO_SCTP)", (socket_type == SOCK_SEQPACKET) ? "SOCK_SEQPACKET" : "SOCK_STREAM"); if ((sk = socket(s_loc.ss_family, socket_type, IPPROTO_SCTP)) < 0 ) { if (do_exit) { fprintf(stderr, "\n\n\t\t*** socket: failed to create" " socket: %s ***\n", strerror(errno)); exit(1); } else { return -1; } } DEBUG_PRINT(DEBUG_MIN, " -> sk=%d\n", sk); memset(&subscribe, 0, sizeof(subscribe)); subscribe.sctp_data_io_event = 1; subscribe.sctp_association_event = 1; error = setsockopt(sk, SOL_SCTP, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)); if (error) { fprintf(stderr, "SCTP_EVENTS: error: %d\n", error); exit(1); } return sk; } /* socket_r() */ int bind_r(int sk, struct sockaddr_storage *saddr) { int error = 0, i = 0; char *host_s, *serv_s; if ((host_s = malloc(NI_MAXHOST)) == NULL) { fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n"); exit(1); } if ((serv_s = malloc(NI_MAXSERV)) == NULL) { fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n"); exit(1); } do { if (i > 0) sleep(1); /* sleep a while before new try... */ error = getnameinfo((struct sockaddr *)saddr, l_len, host_s, NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST); if (error) printf("%s\n", gai_strerror(error)); DEBUG_PRINT(DEBUG_MIN, "\tbind(sk=%d, [a:%s,p:%s]) -- attempt %d/%d\n", sk, host_s, serv_s, i+1, MAX_BIND_RETRYS); error = bind(sk, (struct sockaddr *)saddr, l_len); if (error != 0) { if( errno != EADDRINUSE ) { if (do_exit) { fprintf(stderr, "\n\n\t\t***bind: can " "not bind to %s:%s: %s ****\n", host_s, serv_s, strerror(errno)); exit(1); } else { return -1; } } } i++; if (i >= MAX_BIND_RETRYS) { fprintf(stderr, "Maximum bind() attempts. " "Die now...\n\n"); exit(1); } } while (error < 0 && i < MAX_BIND_RETRYS); return 0; } /* bind_r() */ int bindx_r(int sk, struct sockaddr *addrs, int count, int flag) { int error; int i; struct sockaddr *sa_addr; void *aptr; /* Set the port in every address. */ aptr = addrs; for (i = 0; i < count; i++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: ((struct sockaddr_in *)sa_addr)->sin_port = htons(local_port); aptr += sizeof(struct sockaddr_in); break; case AF_INET6: ((struct sockaddr_in6 *)sa_addr)->sin6_port = htons(local_port); aptr += sizeof(struct sockaddr_in6); break; default: fprintf(stderr, "Invalid address family\n"); exit(1); } } error = sctp_bindx(sk, addrs, count, flag); if (error != 0) { fprintf(stderr, "\n\n\t\t***bindx_r: error adding addrs:" " %s. ***\n", strerror(errno)); exit(1); } return 0; } /* bindx_r() */ int listen_r(int sk, int listen_count) { int error = 0; DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n", sk, listen_count); /* Mark sk as being able to accept new associations */ error = listen(sk, 1); if (error != 0) { if (do_exit) { fprintf(stderr, "\n\n\t\t*** listen: %s ***\n\n\n", strerror(errno)); exit(1); } else return -1; } return 0; } /* listen_r() */ int accept_r(int sk){ socklen_t len = 0; int subsk; DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk); subsk = accept(sk, NULL, &len); if (subsk < 0) { fprintf(stderr, "\n\n\t\t*** accept: %s ***\n\n\n", strerror(errno)); exit(1); } return subsk; } /* accept_r() */ int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) { int error = 0; DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk); /* Mark sk as being able to accept new associations */ error = connect(sk, serv_addr, addrlen); if (error != 0) { if (do_exit) { fprintf(stderr, "\n\n\t\t*** connect: %s ***\n\n\n", strerror(errno)); exit(1); } else return -1; } return 0; } /* connect_r() */ int connectx_r(int sk, struct sockaddr *addrs, int count) { int error; int i; struct sockaddr *sa_addr; void *aptr; /* Set the port in every address. */ aptr = addrs; for (i = 0; i < count; i++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: ((struct sockaddr_in *)sa_addr)->sin_port = htons(remote_port); aptr += sizeof(struct sockaddr_in); break; case AF_INET6: ((struct sockaddr_in6 *)sa_addr)->sin6_port = htons(remote_port); aptr += sizeof(struct sockaddr_in6); break; default: fprintf(stderr, "Invalid address family\n"); exit(1); } } error = sctp_connectx(sk, addrs, count, NULL); if (error != 0) { fprintf(stderr, "\n\n\t\t*** connectx_r: error connecting" " to addrs: %s ***\n", strerror(errno)); exit(1); } return 0; } /* connectx_r() */ int receive_r(int sk, int once) { int recvsk = sk, i = 0, error = 0; char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; struct iovec iov; struct msghdr inmessage; /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) { fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n"); exit(1); } iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); /* Get the messages sent */ while (1) { if (recvsk == sk && socket_type == SOCK_STREAM && role == SERVER) recvsk = accept_r(sk); DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk); error = recvmsg(recvsk, &inmessage, MSG_WAITALL); if (error < 0 && error != EAGAIN) { if (errno == ENOTCONN && socket_type == SOCK_STREAM && role == SERVER) { printf("No association is present now!!\n"); close(recvsk); recvsk = sk; continue; } fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n", strerror(errno)); fflush(stdout); if (do_exit) exit(1); else goto error_out; } else if (error == 0) { if (socket_type == SOCK_STREAM && role == SERVER) { printf("No association is present now!!\n"); close(recvsk); recvsk = sk; continue; } printf("\n\t\trecvmsg() returned 0 !!!!\n"); fflush(stdout); } if (print_message(recvsk, &inmessage, error) > 0) continue; /* got a notification... */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); iov.iov_len = REALLY_BIG; i++; if (once) break; } if (recvsk != sk) close(recvsk); free(iov.iov_base); return 0; error_out: close(sk); free(iov.iov_base); return -1; } /* receive_r () */ int next_order(int state, int pattern) { switch (pattern){ case ORDER_PATTERN_UNORDERED: state = 0; break; case ORDER_PATTERN_ORDERED: state = 1; break; case ORDER_PATTERN_ALTERNATE: state = state ? 0 : 1; break; case ORDER_PATTERN_RANDOM: state = rand() % 2; break; } return state; } int next_stream(int state, int pattern) { switch (pattern){ case STREAM_PATTERN_RANDOM: state = rand() % (max_stream + 1); break; case STREAM_PATTERN_SEQUENTIAL: state = state + 1; if (state > max_stream) state = 0; break; } return state; } int next_msg_size(int msg_cnt) { int msg_size; if (size_arg) { msg_size = size_arg; } else if (test_case < NCASES) { msg_size = msg_sizes[test_case][msg_cnt]; } else { msg_size = (rand() % max_msgsize) + 1; } return msg_size; } /* next_msg_size() */ int next_assoc(int i, int state, int pattern) { int j; int found = 0; _assoc_state *as; switch (pattern){ case ASSOC_PATTERN_RANDOM: state = rand() % tosend; break; case ASSOC_PATTERN_SEQUENTIAL: state = state + 1; if (state >= tosend) state = 0; break; } as = poll_sks[i].assoc_state; j = state; do { if (as[j].msg_sent < repeat_count) { found = 1; break; } if (++j >= tosend) { j = 0; } } while (j != state); if (found) { return j; } else { return -1; } } /* next_assoc() */ int send_r(int sk, int stream, int order, int send_size, int assoc_i) { int error = 0; struct msghdr outmsg; struct iovec iov; char *message = NULL; int msglen = 0; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sinfo; if (send_size > 0) { message = build_msg(send_size); msglen = strlen(message) + 1; iov.iov_base = message; iov.iov_len = msglen; } else { if (do_exit) { exit(1); } else { goto error_out; } } outmsg.msg_name = &s_rem; outmsg.msg_namelen = sizeof(struct sockaddr_storage); outmsg.msg_iov = &iov; outmsg.msg_iovlen = 1; outmsg.msg_control = outcmsg; outmsg.msg_controllen = sizeof(outcmsg); outmsg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmsg); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmsg.msg_controllen = cmsg->cmsg_len; sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); sinfo->sinfo_ppid = rand(); sinfo->sinfo_stream = stream; sinfo->sinfo_flags = 0; if (!order) sinfo->sinfo_flags = SCTP_UNORDERED; if (timetolive) sinfo->sinfo_timetolive = timetolive; DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n", sk, assoc_i, send_size); DEBUG_PRINT(DEBUG_MAX, "\t SNDRCV"); if (DEBUG_MAX == debug_level) { printf("(stream=%u ", sinfo->sinfo_stream); printf("flags=0x%x ", sinfo->sinfo_flags); printf("ppid=%u\n", sinfo->sinfo_ppid); } /* Send to our neighbor. */ error = sendmsg(sk, &outmsg, MSG_WAITALL); if (error != msglen) { fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n", strerror(errno)); fflush(stdout); if (do_exit) { exit(1); } else { if (!drain) goto error_out; } } if (send_size > 0) free(message); return 0; error_out: if (send_size > 0) free(message); return -1; } /* send_r() */ int close_r(int sk) { int error = 0; DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk); error = close(sk); if (error != 0) { if (do_exit) { fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n", strerror(errno)); exit(1); } else { return -1; } } fflush(stdout); return 0; } /* close_r() */ void server(int sk) { if (max_msgsize > DEFAULT_MAX_WINDOW) { if (setsockopt(sk, SOL_SOCKET, SO_RCVBUF, &max_msgsize, sizeof(max_msgsize)) < 0) { perror("setsockopt(SO_RCVBUF)"); exit(1); } } receive_r(sk, 0); } /* server() */ void client(int sk) { int msg_size; int i; for (i = 0; i < msg_cnt; i++) { msg_size = next_msg_size(i); order_state = next_order(order_state, order_pattern); stream_state = next_stream(stream_state, stream_pattern); if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) { close(sk); break; } /* The sender is echoing so do discard the echoed data. */ if (drain) { receive_r(sk, 1); } } } /* client() */ void mixed_mode_test(void) { int error, i, j, max_fd, sks, size; int assoc_i, n_msg_size, n_order, n_stream; int done = 0; fd_set *ibitsp = NULL, *obitsp = NULL, *xbitsp = NULL; char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; struct iovec iov; struct msghdr inmessage; _assoc_state *as; /* Set up the listeners. If listeners is 0, set up one socket for * transmitting only. */ iov.iov_base = NULL; max_fd = -1; sks = (0 == listeners) ? 1 : listeners; memset(poll_sks, 0, sizeof(sks * sizeof(_poll_sks))); for (i = 0; i < sks; i++) { poll_sks[i].sk = socket_r(); if (s_loc.ss_family == AF_INET6) ( (struct sockaddr_in6 *)&s_loc)->sin6_port = htons(local_port + i); else ( (struct sockaddr_in *)&s_loc)->sin_port = htons(local_port + i); bind_r(poll_sks[i].sk, &s_loc); if (listeners) { listen_r(poll_sks[i].sk, 100); } if (max_msgsize > DEFAULT_MAX_WINDOW) { if (setsockopt(poll_sks[i].sk, SOL_SOCKET, SO_RCVBUF, &max_msgsize, sizeof(max_msgsize)) < 0) { perror("setsockopt(SO_RCVBUF)"); exit(1); } } if (tosend) { if ((poll_sks[i].assoc_state = (_assoc_state *)malloc( sizeof(_assoc_state) * tosend)) == NULL) { printf("Can't allocate memory.\n"); goto clean_up; } memset(poll_sks[i].assoc_state, 0, sizeof(_assoc_state) * tosend); } if (poll_sks[i].sk > max_fd) { max_fd = poll_sks[i].sk; } } size = howmany(max_fd + 1, NFDBITS) * sizeof(fd_mask); if ((ibitsp = (fd_set *)malloc(size)) == NULL) { printf("Can't allocate memory.\n"); goto clean_up; } if ((obitsp = (fd_set *)malloc(size)) == NULL) { printf("Can't allocate memory.\n"); goto clean_up; } if ((xbitsp = (fd_set *)malloc(size)) == NULL) { printf("Can't allocate memory.\n"); goto clean_up; } memset(ibitsp, 0, size); memset(obitsp, 0, size); memset(xbitsp, 0, size); /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) { fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n"); goto clean_up; } iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); /* Set up the remote port number per association for output. */ for (i = 0; i < sks; i++) { as = poll_sks[i].assoc_state; for (j = 0; j < tosend; j++) { as[j].rem_port = remote_port + j; } } while (!done) { for (i = 0; i < sks; i++) { FD_SET(poll_sks[i].sk, ibitsp); FD_SET(poll_sks[i].sk, obitsp); FD_SET(poll_sks[i].sk, xbitsp); } if ((error = select(max_fd + 1, ibitsp, obitsp, xbitsp, (struct timeval *)0)) < 0) { fprintf(stderr, "\n\t\t*** select() failed "); fprintf(stderr, "with error: %s\n\n", strerror(errno)); fflush(stdout); goto clean_up; } for (i = 0; i < sks; i++) { /* Is there anything to read from the socket? */ if (listeners && FD_ISSET(poll_sks[i].sk, ibitsp)) { FD_CLR(poll_sks[i].sk, ibitsp); error = recvmsg(poll_sks[i].sk, &inmessage, MSG_WAITALL); if (error < 0) { fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n", strerror(errno)); fflush(stdout); goto clean_up; } else if (error == 0) { printf("\n\t\trecvmsg() returned "); printf("0 !!!!\n"); fflush(stdout); } print_message(poll_sks[i].sk, &inmessage, error); inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); iov.iov_len = REALLY_BIG; } /* Is this socket writeable? */ if (tosend && FD_ISSET(poll_sks[i].sk, obitsp)) { FD_CLR(poll_sks[i].sk, obitsp); /* Pick an association. */ assoc_i = next_assoc(i, poll_sks[i].assoc_i, assoc_pattern); if (assoc_i < 0) { /* No work to do on any associations. * We are probably done. */ if (!listeners) { done = 1; } continue; } poll_sks[i].assoc_i = assoc_i; as = poll_sks[i].assoc_state; n_msg_size = next_msg_size(as[assoc_i].msg_cnt); n_order = as[assoc_i].order_state = next_order(as[assoc_i].order_state, order_pattern); n_stream = as[assoc_i].stream_state = next_stream(as[assoc_i].stream_state, stream_pattern); /* Set the destination port. */ if (s_rem.ss_family == AF_INET6) ( (struct sockaddr_in6 *)&s_rem)-> sin6_port = htons(as[assoc_i].rem_port); else ( (struct sockaddr_in *)&s_rem)-> sin_port = htons(as[assoc_i].rem_port); /* Send a message thru the association. */ if (send_r(poll_sks[i].sk, n_stream, n_order, n_msg_size, assoc_i) < 0) { /* Don't increment counter if there * is a problem of sending. */ continue; } /* Increment counters. */ if (++as[assoc_i].msg_cnt >= MSG_CNT) { as[assoc_i].msg_cnt = 0; } if (++as[assoc_i].msg_sent >= repeat_count) { fprintf(stderr, "Association #%d in ", assoc_i); fprintf(stderr, "sk=%d has ", poll_sks[i].sk); fprintf(stderr, "completed %d msg as ", as[assoc_i].msg_sent); fprintf(stderr, "cycle %d.\n", ++as[assoc_i].cycle); /* In the mixed mode, -x not only * specify the longer repeat cycle, * but it also mean to run the test * forever. */ if (xflag) { as[assoc_i].msg_sent = 0; } } } } } clean_up: for (i = 0; i < sks; i++) { close(poll_sks[i].sk); if (poll_sks[i].assoc_state) { free(poll_sks[i].assoc_state); } } if (ibitsp) free(ibitsp); if (obitsp) free(obitsp); if (xbitsp) free(xbitsp); if (iov.iov_base) free(iov.iov_base); } /* mixed_mode_test() */ void start_test(int role) { int sk; int i = 0; DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n"); repeat_count = repeat; if (MIXED == role) { repeat_count = repeat_count * msg_cnt; /* Repeat per assoc. */ mixed_mode_test(); return; } sk = socket_r(); bind_r(sk, &s_loc); /* Do we need to do bindx() to add any additional addresses? */ if (bindx_add_addrs) bindx_r(sk, bindx_add_addrs, bindx_add_count, SCTP_BINDX_ADD_ADDR); if (role == SERVER) { listen_r(sk, 100); } else { if (socket_type == SOCK_STREAM && connectx_count == 0) connect_r(sk, (struct sockaddr *)&s_rem, r_len); if (connectx_count != 0) connectx_r(sk, connectx_addrs, connectx_count); } if (!debug_level) { printf(" "); } for(i = 0; i < repeat_count; i++) { if (role == SERVER) { DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.\n"); server(sk); } else { DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n", i+1, repeat_count); client(sk); } fflush(stdout); } close_r(sk); } /* start_test() */ int main(int argc, char *argv[]) { int c; char *interface = NULL; struct sockaddr_in *t_addr; struct sockaddr_in6 *t_addr6; struct sockaddr *tmp_addrs = NULL; /* Parse the arguments. */ while ((c = getopt(argc, argv, ":H:L:P:S:a:h:p:c:d:lm:sx:X:o:t:M:r:w:Di:TB:C:O:")) >= 0 ) { switch (c) { case 'H': local_host = optarg; break; case 'L': role = MIXED; listeners = atoi(optarg); if (listeners > MAX_POLL_SKS) { usage(argv[0]); exit(1); } break; case 'P': local_port = atoi(optarg); break; case 'S': role = MIXED; tosend = atoi(optarg); if (tosend > MAX_POLL_SKS) { usage(argv[0]); exit(1); } break; case 'a': assoc_pattern = atoi(optarg); if (assoc_pattern < ASSOC_PATTERN_SEQUENTIAL || assoc_pattern > ASSOC_PATTERN_RANDOM ) { usage(argv[0]); exit(1); } break; case 'h': remote_host = optarg; break; case 'D': drain = 1; do_exit = 0; break; case 'p': remote_port = atoi(optarg); break; case 's': if (role != NOT_DEFINED) { printf("%s: only -s or -l\n", argv[0]); usage(argv[0]); exit(1); } role = CLIENT; break; case 'l': if (role != NOT_DEFINED) { printf("%s: only -s or -l\n", argv[0]); usage(argv[0]); exit(1); } role = SERVER; break; case 'd': debug_level = atoi(optarg); if (debug_level < DEBUG_NONE || debug_level > DEBUG_MAX) { usage(argv[0]); exit(1); } break; case 'x': repeat = atoi(optarg); if (!repeat) { xflag = 1; repeat = BIG_REPEAT; } break; case 'X': msg_cnt = atoi(optarg); if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) { usage(argv[0]); exit(1); } break; case 'c': test_case = atoi(optarg); if (test_case > NCASES) { usage(argv[0]); exit(1); } if (test_case < 0) { size_arg = -test_case; } break; case 'o': order_pattern = atoi(optarg); if (order_pattern < ORDER_PATTERN_UNORDERED || order_pattern > ORDER_PATTERN_RANDOM ) { usage(argv[0]); exit(1); } break; case 'O': timetolive = atoi(optarg); if (timetolive < 0) { usage(argv[0]); exit(1); } break; case 't': stream_pattern = atoi(optarg); if (stream_pattern < STREAM_PATTERN_SEQUENTIAL || stream_pattern > STREAM_PATTERN_RANDOM ) { usage(argv[0]); exit(1); } break; case 'M': max_stream = atoi(optarg); if (max_stream < 0 || max_stream >= (1<<16)) { usage(argv[0]); exit(1); } break; case 'r': seed = atoi(optarg); break; case 'm': max_msgsize = atoi(optarg); #if 0 if ((max_msgsize < DEFAULT_MIN_WINDOW) || (max_msgsize > 65515)) { usage(argv[0]); exit(1); } #endif break; case 'i': interface = optarg; if_index = if_nametoindex(interface); if (!if_index) { printf("Interface %s unknown\n", interface); exit(1); } break; case 'T': socket_type = SOCK_STREAM; break; case 'B': tmp_addrs = append_addr(optarg, bindx_add_addrs, &bindx_add_count); if (NULL == tmp_addrs) { fprintf(stderr, "No memory to add "); fprintf(stderr, "%s\n", optarg); exit(1); } bindx_add_addrs = tmp_addrs; break; case 'C': tmp_addrs = append_addr(optarg, connectx_addrs, &connectx_count); if (NULL == tmp_addrs) { fprintf(stderr, "No memory to add "); fprintf(stderr, "%s\n", optarg); exit(1); } connectx_addrs = tmp_addrs; break; case '?': default: usage(argv[0]); exit(0); } } /* while() */ if (NOT_DEFINED == role) { usage(argv[0]); exit(1); } if (SERVER == role && NULL == local_host && remote_host != NULL) { fprintf (stderr, "%s: Server needs local address, " "not remote address\n", argv[0]); usage(argv[0]); exit(1); } if (CLIENT == role && NULL == remote_host && connectx_count == 0) { fprintf (stderr, "%s: Client needs at least remote address " "& port\n", argv[0]); usage(argv[0]); exit(1); } if (MIXED == role) { if (listeners && NULL == local_host) { fprintf (stderr, "%s: Servers need local address\n", argv[0]); usage(argv[0]); exit(1); } if (tosend && NULL == remote_host) { fprintf (stderr, "%s: Clients need remote address ", argv[0]); fprintf (stderr, "& port\n"); usage(argv[0]); exit(1); } } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf (stderr, "\n"); usage(argv[0]); exit(1); } if (remote_host != NULL && connectx_count != 0) { fprintf(stderr, "%s: You can not provide both -h and -C options.\n", argv[0]); usage(argv[0]); exit(1); } if (remote_host != NULL && remote_port != 0) { struct addrinfo *res; int error; char *host_s, *serv_s; if ((host_s = malloc(NI_MAXHOST)) == NULL) { fprintf(stderr, "\n*** host_s malloc failed!!! ***\n"); exit(1); } if ((serv_s = malloc(NI_MAXSERV)) == NULL) { fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n"); exit(1); } error = getaddrinfo(remote_host, 0, NULL, &res); if (error) { printf("%s.\n", gai_strerror(error)); usage(argv[0]); exit(1); } switch (res->ai_family) { case AF_INET: t_addr = (struct sockaddr_in *)&s_rem; t_addr->sin_family = AF_INET; t_addr->sin_port = htons(remote_port); inet_pton(AF_INET, remote_host, &t_addr->sin_addr); r_len = sizeof (struct sockaddr_in); #ifdef __FreeBSD__ t_addr->sin_len = r_len; #endif break; case AF_INET6: t_addr6 = (struct sockaddr_in6 *)&s_rem; if (interface) t_addr6->sin6_scope_id = if_nametoindex(interface); t_addr6->sin6_family = AF_INET6; t_addr6->sin6_port = htons(remote_port); inet_pton(AF_INET6, remote_host, &t_addr6->sin6_addr); r_len = sizeof (struct sockaddr_in6); #ifdef __FreeBSD__ t_addr6->sin6_len = r_len; #endif break; } getnameinfo((struct sockaddr *)&s_rem, r_len, host_s, NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST); DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n", host_s, serv_s, res->ai_family); } if (connectx_count != 0) { switch (connectx_addrs->sa_family) { case AF_INET: t_addr = (struct sockaddr_in *)&s_rem; r_len = sizeof(struct sockaddr_in); memcpy(t_addr, connectx_addrs, r_len); t_addr->sin_port = htons(remote_port); break; case AF_INET6: t_addr6 = (struct sockaddr_in6 *)&s_rem; r_len = sizeof(struct sockaddr_in6); memcpy(t_addr6, connectx_addrs, r_len); t_addr6->sin6_port = htons(remote_port); break; } } if (local_host != NULL) { struct addrinfo *res; int error; char *host_s, *serv_s; struct sockaddr_in *t_addr; struct sockaddr_in6 *t_addr6; if ((host_s = malloc(NI_MAXHOST)) == NULL) { fprintf(stderr, "\n*** host_s malloc failed!!! ***\n"); exit(1); } if ((serv_s = malloc(NI_MAXSERV)) == NULL) { fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n"); exit(1); } if (strcmp(local_host, "0") == 0) local_host = "0.0.0.0"; error = getaddrinfo(local_host, 0, NULL, &res); if (error) { printf("%s.\n", gai_strerror(error)); usage(argv[0]); exit(1); } switch (res->ai_family) { case AF_INET: t_addr = (struct sockaddr_in *)&s_loc; t_addr->sin_family = AF_INET; t_addr->sin_port = htons(local_port); inet_pton(AF_INET, local_host, &t_addr->sin_addr); l_len = sizeof (struct sockaddr_in); #ifdef __FreeBSD__ t_addr->sin_len = l_len; #endif break; case AF_INET6: t_addr6 = (struct sockaddr_in6 *)&s_loc; if (interface) t_addr6->sin6_scope_id = if_nametoindex(interface); t_addr6->sin6_family = AF_INET6; t_addr6->sin6_port = htons(local_port); inet_pton(AF_INET6, local_host, &t_addr6->sin6_addr); l_len = sizeof (struct sockaddr_in6); #ifdef __FreeBSD__ t_addr6->sin6_len = l_len; #endif break; } error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s, NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST); if (error) printf("%s..\n", gai_strerror(error)); DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n", host_s, serv_s, res->ai_family); } /* A half-hearted attempt to seed rand() */ if (seed == 0 ) { seed = time(0); DEBUG_PRINT(DEBUG_NONE, "seed = %d\n", seed); } srand(seed); /* Let the testing begin. */ start_test(role); return 0; } /* main() */ lksctp-tools-1.0.16+dfsg.orig/src/apps/sctp_xconnect.c0000644000175000017500000003236212300634451022455 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2003 * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * * Written or modified by: * Ryan Layer */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; #define MAXHOSTNAME 64 #define MAXCLIENTNUM 10000 #define TRUE 1 #define SERVER 1 #define CLIENT 0 #define NOT_DEFINED -1 int mode = NOT_DEFINED; int assoc_num, remote_port, local_port; int active = 0; char *local_host = NULL; char *remote_host = NULL; sockaddr_storage_t client_loop, server_loop; struct hostent *hst; char big_buffer[REALLY_BIG]; void usage(char *argv0); void parse_arguments(int argc, char*argv[]); void data_received(struct msghdr *inmessage, int len, int stream, int server_socket); int event_received(struct msghdr *inmessage, int assoc_num); void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds); void server_mode(void); void client_mode(void); /* Print the syntax/usage */ void usage(char *argv0) { printf("usage: %s -H localhost -P localport -l|c [-h remotehost]\n" "\t\t[-p remoteport] [-a] [-n ]\n" " -H\t\tspecify a local address.\n" " -P\t\tspecify the local port number to be used\n" " -l\t\trun in server mode.\n" " -c\t\trun in client mode.\n" " -h\t\tspecify the peer address.\n" " -p\t\tspecify the port number for the peer address.\n" " -a\t\tactively generate traffic with the server.\n" " -n\t\tspecify the number of associations to create.\n", argv0); } /* Parse command line options */ void parse_arguments(int argc, char*argv[]) { int c; while ((c = getopt(argc, argv, ":H:P:ach:ln:p:")) >= 0) { switch (c) { case 'H': local_host = optarg; break; case 'P': local_port = atoi(optarg); break; case 'c': if (mode == NOT_DEFINED) mode = CLIENT; else { usage(argv[0]); exit(0); } break; case 'a': active = 1; break; case 'h': remote_host = optarg; break; case 'l': if (mode == NOT_DEFINED) mode = SERVER; else { usage(argv[0]); exit(0); } break; case 'n': assoc_num = atoi(optarg); break; case 'p': remote_port = atoi(optarg); break; default: usage(argv[0]); exit(0); } } /* while() */ if (mode == CLIENT) { if (assoc_num) { if (assoc_num > MAXCLIENTNUM) { printf("The number of associations indicated " "is greater than the"); printf("max number of associations " "allowed(%d).", MAXCLIENTNUM); usage(argv[0]); exit(0); } } else assoc_num = 1; if (remote_host && remote_port) { hst = gethostbyname(remote_host); memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0], sizeof(server_loop.v4.sin_addr)); server_loop.v4.sin_family = AF_INET; server_loop.v4.sin_port = htons(remote_port); } else { printf("Remote host and remote port must be defined " "in client mode\n"); usage(argv[0]); exit(0); } if (local_host) { hst = gethostbyname(local_host); memcpy(&client_loop.v4.sin_addr, hst->h_addr_list[0], sizeof(client_loop.v4.sin_addr)); } else client_loop.v4.sin_addr.s_addr = INADDR_ANY; if (local_port) client_loop.v4.sin_port = htons(local_port); else client_loop.v4.sin_port = 0; client_loop.v4.sin_family = AF_INET; } else if (mode == SERVER) { if (active) { printf("This option if for client use only"); usage(argv[0]); exit(0); } if (remote_host || remote_port) { printf("Remote values not needed in server mode.\n"); usage(argv[0]); exit(0); } if (local_host) { hst = gethostbyname(local_host); memcpy(&server_loop.v4.sin_addr, hst->h_addr_list[0], sizeof(server_loop.v4.sin_addr)); } else server_loop.v4.sin_addr.s_addr = INADDR_ANY; if (local_port) server_loop.v4.sin_port = htons(local_port); else { printf("Specify a local port in server mode.\n"); usage(argv[0]); exit(0); } server_loop.v4.sin_family = AF_INET; } else { printf("Must assisgn a client or server mode.\n"); usage(argv[0]); exit(0); } } /* parse_arguments() */ /* Handle data recieved */ void data_received(struct msghdr *inmessage, int len, int stream, int socket) { int ppid, error; char *ping = "PING"; if (mode == SERVER) { ppid = rand(); error = sctp_sendmsg(socket, inmessage->msg_iov->iov_base, len, (struct sockaddr *)inmessage->msg_name, inmessage->msg_namelen, ppid, 0, stream, 0, 0); if (error < 0) { printf("Send Failure: %s.\n", strerror(errno)); DUMP_CORE; } } else { ppid = rand(); printf("Data Received by socket #: %d.\n", socket); printf("\tMessage = %s\n", (char *)inmessage->msg_iov->iov_base); if (active) { sctp_sendmsg(socket, ping, strlen(ping) + 1, (struct sockaddr *)&server_loop, sizeof (server_loop), ppid, 0, stream, 0, 0); } } } /* This will print what type of SCTP_ASSOC_CHANGE state that was recieved */ void print_sctp_sac_state(struct msghdr *msg) { char *data; union sctp_notification *sn; if (msg->msg_flags & MSG_NOTIFICATION) { data = (char *)msg->msg_iov[0].iov_base; sn = (union sctp_notification *)data; switch (sn->sn_assoc_change.sac_state) { case SCTP_COMM_UP: printf("SCTP_COMM_UP\n"); break; case SCTP_COMM_LOST: printf("SCTP_COMM_LOST\n"); break; case SCTP_RESTART: printf("SCTP_RESTART"); break; case SCTP_SHUTDOWN_COMP: printf("SCTP_SHUTDOWN_COMP\n"); break; case SCTP_CANT_STR_ASSOC: printf("SCTP_CANT_STR_ASSOC\n"); break; default: break; } } } /* void print_sctp_sac_state() */ /* Tests what type of MSG_NOTIFICATION has been received. * For now this fucntion only works with SCTP_ASSOC_CHANGE * types, but can be easily expanded. * * Will return... * -1 if the msg_flags is not MSG_NOTIFICATION * 0 if the MSG_NOTIFICATION type differs from the type * passed into the additional variable * 1 if the MSG_NOTIFICATION type matches the type * passed into the additional variable */ int test_check_notification_type(struct msghdr *msg, uint16_t sn_type, uint32_t additional) { char *data; union sctp_notification *sn; if (!(msg->msg_flags & MSG_NOTIFICATION)) { return -1; } else { /* Fixup for testframe. */ data = (char *)msg->msg_iov[0].iov_base; sn = (union sctp_notification *)data; if (sn->sn_header.sn_type != sn_type) return 0; else if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) if (sn->sn_assoc_change.sac_state == additional) return 1; return 0; } } /* Determine the type of event and make correct adjustments to the * association count */ int event_received(struct msghdr *inmessage, int assoc_num) { int error; printf("Event Received\n"); print_sctp_sac_state(inmessage); if (mode == SERVER) { /* Test type of Event */ error = test_check_notification_type(inmessage, SCTP_ASSOC_CHANGE, SCTP_COMM_UP); if (error > 0) { assoc_num++; printf("Assosiation Established: count = %d.\n", assoc_num); } else { error = test_check_notification_type(inmessage, SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); if (error > 0) { assoc_num--; printf("Assosiation Shutdown: count = %d.\n", assoc_num); } } } return assoc_num; } void server_mode() { sockaddr_storage_t msgname; int server_socket, error, stream; int assoc_num =0; struct msghdr inmessage; struct iovec iov; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; printf("Running in Server Mode...\n"); 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; inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof (msgname); stream = 1; server_socket = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if (server_socket < 0) { printf("Socket Failure: %s.\n", strerror(errno)); DUMP_CORE; } error = bind(server_socket, &server_loop.sa, sizeof(server_loop)); if (error != 0 ) { printf("Bind Failure: %s.\n", strerror(errno)); DUMP_CORE; } error = listen(server_socket, 1); if (error != 0) { printf("Listen Failure: %s.\n", strerror(errno)); DUMP_CORE; } while (TRUE) { error = recvmsg(server_socket, &inmessage, MSG_WAITALL); if (error < 0) { printf("Receive Failure: %s\n", strerror(errno)); } else { if (inmessage.msg_flags & MSG_NOTIFICATION) assoc_num = event_received(&inmessage, assoc_num); else data_received(&inmessage, error, stream, server_socket); } } } void client_mode() { int i, error, stream, max_socket = 0; uint32_t ppid = 0; int client_socket[assoc_num]; char *message = "Awake"; fd_set rfds; struct timeval tv; stream = 1; printf("Running in Client Mode...\n"); /* Create the sockets */ for (i = 0; i < assoc_num; i++) { client_socket[i] = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); if (client_socket[i] < 0 ){ printf("Socket Failure: %s.\n", strerror(errno)); DUMP_CORE; } if (local_port) { error = bind(client_socket[i], &client_loop.sa, sizeof(client_loop)); if (error < 0) { printf("Bind Failure: %s\n", strerror(errno)); DUMP_CORE; } } printf("Create Socket #: %d\n", client_socket[i]); /* Connect to server and send initial message */ error = connect(client_socket[i], &server_loop.sa, sizeof(server_loop)); if (error < 0){ printf("Connect Failure: %s.\n", strerror(errno)); DUMP_CORE; } max_socket = client_socket[i]; ppid++; /* Send initial message */ error = sctp_sendmsg(client_socket[i], message, strlen(message) + 1, (struct sockaddr *)&server_loop, sizeof(server_loop), ppid, 0, stream, 0, 0); if (error < 0 ) { printf("Send Failure: %s.\n", strerror(errno)); DUMP_CORE; } } while (TRUE){ /* Clear the set for select() */ FD_ZERO(&rfds); /* Set time out values for select() */ tv.tv_sec = 5; tv.tv_usec = 0; /* Add the sockets select() will examine */ for (i = 0; i < assoc_num; i++) { FD_SET(client_socket[i], &rfds); } /* Wait until there is data to be read from one of the * sockets, or until the timer expires */ error = select(max_socket + 1, &rfds, NULL, NULL, &tv); if (error < 0) { printf("Select Failure: %s.\n", strerror(errno)); DUMP_CORE; } else if (error) { /* Loop through the array of sockets to find the ones *that have information to be read */ process_ready_sockets(client_socket, assoc_num, &rfds); } } } void process_ready_sockets(int client_socket[], int assoc_num, fd_set *rfds) { int i, stream, error; struct msghdr inmessage; struct iovec iov; char incmsg[CMSG_SPACE(sizeof (sctp_cmsg_data_t))]; sockaddr_storage_t msgname; /* Setup inmessage to be able to receive in incomming message */ 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; inmessage.msg_controllen = sizeof (incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof (msgname); stream = 1; for( i = 0; i < assoc_num; i++) { if (FD_ISSET(client_socket[i], rfds)) { error = recvmsg(client_socket[i], &inmessage, MSG_WAITALL); if (error < 0) printf("Receive Failure: %s\n", strerror(errno)); else { /* Test to find the type of message that was read(event/data) */ if (inmessage.msg_flags & MSG_NOTIFICATION) event_received(&inmessage, 0); else data_received(&inmessage, error, stream, client_socket[i]); } } } } int main(int argc, char *argv[]) { parse_arguments(argc, argv); if (mode == SERVER) { server_mode(); } else if (mode == CLIENT){ client_mode(); } exit(1); } lksctp-tools-1.0.16+dfsg.orig/src/apps/bindx_test.c0000644000175000017500000000655712300634451021755 0ustar michaelmichael /* -*-c-*- ** ** sctp-tools: Another bindx test. ** ** $Id: bindx_test.c,v 1.1.1.1 2002/08/06 22:31:05 inaky Exp $ ** ** Distributed under the terms of the GPL v2.0 as described in ** $top_srcdir/COPYING. ** ** (C) Copyright IBM Corp. 2003 ** (C) 2002 Intel Corporation ** Iñaky Pérez-González : ** Sridhar Samudrala */ #define _GNU_SOURCE /* GNU extensions */ #include /* malloc() */ #include /* inet_pton() */ #include #include /* socket() */ #include /* fprintf */ #include /* sockaddr_in */ #include /* close() */ #include /* strchr() */ #include /* bindx() */ /* Global stuff */ #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif /*! Main function: initialize, setup, run the main loop ** ** */ int main (int argc, char **argv) { void *addr_buf, *buf_ptr; void *addr_buf_size = 0; size_t addrs, cnt; int sd, result, port; if (argc < 3) { fprintf(stderr, "Usage: bindx_test PORT IPADDR1 [IPADDR2 [...]]\n"); return 1; } port = atoi(argv[1]); printf("bindx_test: INFO: Port is %d\n", port); /* Allocate the maximum space for the specified no. of addresses. * Assume all of them are v6 addresses. */ addr_buf = malloc((argc -2) * sizeof(struct sockaddr_in6)); if (addr_buf == NULL) { perror("bindx_test: ERROR: addr buf allocation failed"); return 1; } /* Get the addresses from the cmd line */ addrs = 0; /* healthy address iterator [and total counter] */ cnt = 2; /* argument iterator */ buf_ptr = addr_buf; while (cnt < argc) { printf("bindx_test: INFO: Arg %zu: %s", cnt, argv[cnt]); fflush(stderr); if (strchr(argv[cnt], ':')) { struct sockaddr_in6 *sa6; sa6 = (struct sockaddr_in6 *)buf_ptr; printf(" IPv6 address number %zu", addrs); sa6->sin6_family = AF_INET6; sa6->sin6_port = port; if (inet_pton(AF_INET6, argv[cnt], &sa6->sin6_addr)) { addrs++; addr_buf_size += sizeof(struct sockaddr_in6); buf_ptr += sizeof(struct sockaddr_in6); } else printf(" error"); } else if (strchr(argv[cnt], '.')) { struct sockaddr_in *sa; sa = (struct sockaddr_in *)buf_ptr; printf (" IPv4 address number %zu", addrs); sa->sin_family = AF_INET; sa->sin_port = port; if (inet_pton (AF_INET, argv[cnt], &sa->sin_addr)) { addrs++; addr_buf_size += sizeof(struct sockaddr_in); buf_ptr += sizeof(struct sockaddr_in); } else printf (" error"); } else printf (" Unknown"); putchar ('\n'); cnt++; } printf ("bindx_test: INFO: Got %zu addrs\n", addrs); /* Create the socket */ sd = socket(PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP); if (sd == -1) { perror("bindx_test: ERROR: Cannot open socket"); return 1; } /* add all */ result = sctp_bindx(sd, (struct sockaddr *)addr_buf, addrs, SCTP_BINDX_ADD_ADDR); if (result == -1) perror("bindx_test: ERROR: bindx addition error"); else { printf("bindx_test: OK: bindx address addition\n"); /* remove all but the last */ result = sctp_bindx(sd, (struct sockaddr *)addr_buf, addrs-1, SCTP_BINDX_REM_ADDR); if (result == -1) perror("bindx_test: ERROR: bindx address removal"); else printf("bindx_test: OK: bindx address removal\n"); } close(sd); free(addr_buf); return result; } lksctp-tools-1.0.16+dfsg.orig/src/apps/sctp_status.c0000644000175000017500000005265112300634451022162 0ustar michaelmichael/* SCTP kernel reference Implementation * (C) Copyright Fujitsu Ltd. 2008, 2009 * * The SCTP reference 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 reference 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 * * 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: * Wei Yongjun */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_SEC 0 #define DEFAULT_USEC 5000 #define REALLY_BIG 65536 #define SERVER 0 #define CLIENT 1 #define NOT_DEFINED 666 #define DEBUG_NONE 0 #define DEBUG_MIN 1 #define DEBUG_MAX 2 #define ORDER_PATTERN_UNORDERED 0 #define ORDER_PATTERN_ORDERED 1 #define ORDER_PATTERN_ALTERNATE 2 #define ORDER_PATTERN_RANDOM 3 #define STREAM_PATTERN_SEQUENTIAL 0 #define STREAM_PATTERN_RANDOM 1 #define MAX_BIND_RETRYS 10 #define BIG_REPEAT 1000000 #define REPEAT 10 #define DEFAULT_MAX_WINDOW 32768 #define DEFAULT_MIN_WINDOW 1500 #define MSG_CNT 10 #define DEBUG_PRINT(level, print_this...) \ { \ if (debug_level >= level) { \ fprintf(stdout, print_this); \ fflush(stdout); \ } \ } /* DEBUG_PRINT */ char *local_host = NULL; int local_port = 0; char *remote_host = NULL; int remote_port = 0; struct sockaddr_storage s_rem, s_loc; int r_len, l_len; int size_arg = 0; int debug_level = DEBUG_NONE; int order_pattern = ORDER_PATTERN_UNORDERED; int order_state = 0; int stream_pattern = STREAM_PATTERN_SEQUENTIAL; int stream_state = 0; int repeat = REPEAT; int repeat_count = 0; int max_msgsize = DEFAULT_MAX_WINDOW; int msg_cnt = MSG_CNT; int drain = 0; int max_stream = 0; int gsk = -1; int period = 1; char *statusfile = NULL; void printstatus(int sk); void sighandler(int signo); void settimerhandle(void); void usage(char *argv0); void start_test(int role); unsigned char msg[] = "012345678901234567890123456789012345678901234567890"; /* Convenience structure to determine space needed for cmsg. */ typedef union { struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcvinfo; } _sctp_cmsg_data_t; int main(int argc, char *argv[]) { int c, role = NOT_DEFINED; char *interface = NULL; struct sockaddr_in *t_addr; struct sockaddr_in6 *t_addr6; /* Parse the arguments. */ while ((c = getopt(argc, argv, ":H:L:P:h:p:c:d:lm:sx:X:o:M:Di:I:f:")) >= 0 ) { switch (c) { case 'H': local_host = optarg; break; case 'P': local_port = atoi(optarg); break; case 'h': remote_host = optarg; break; case 'p': remote_port = atoi(optarg); break; case 'l': if (role != NOT_DEFINED) { printf("%s: only -s or -l\n", argv[0]); usage(argv[0]); exit(1); } role = SERVER; break; case 's': if (role != NOT_DEFINED) { printf("%s: only -s or -l\n", argv[0]); usage(argv[0]); exit(1); } role = CLIENT; break; case 'D': drain = 1; break; case 'd': debug_level = atoi(optarg); if (debug_level < DEBUG_NONE || debug_level > DEBUG_MAX) { usage(argv[0]); exit(1); } break; case 'I': period = atoi(optarg); if (period < 0) { usage(argv[0]); exit(1); } break; case 'x': repeat = atoi(optarg); if (!repeat) { repeat = BIG_REPEAT; } break; case 'X': msg_cnt = atoi(optarg); if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) { usage(argv[0]); exit(1); } break; case 'c': size_arg = atoi(optarg); if (size_arg < 0) { usage(argv[0]); exit(1); } break; case 'o': order_pattern = atoi(optarg); if (order_pattern < ORDER_PATTERN_UNORDERED || order_pattern > ORDER_PATTERN_RANDOM ) { usage(argv[0]); exit(1); } break; case 'M': max_stream = atoi(optarg); if (max_stream < 0 || max_stream >= (1<<16)) { usage(argv[0]); exit(1); } break; case 'm': max_msgsize = atoi(optarg); break; case 'i': interface = optarg; break; case 'f': statusfile = optarg; break; case '?': default: usage(argv[0]); exit(0); } } /* while() */ if (NOT_DEFINED == role) { usage(argv[0]); exit(1); } if (SERVER == role && NULL == local_host && remote_host != NULL) { fprintf(stderr, "%s: Server needs local address, " "not remote address\n", argv[0]); usage(argv[0]); exit(1); } if (CLIENT == role && NULL == remote_host) { fprintf(stderr, "%s: Client needs at least remote address " "& port\n", argv[0]); usage(argv[0]); exit(1); } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf (stderr, "\n"); usage(argv[0]); exit(1); } if (remote_host != NULL && remote_port != 0) { struct addrinfo *res; int error; char *host_s, *serv_s; if ((host_s = malloc(NI_MAXHOST)) == NULL) { fprintf(stderr, "\n*** host_s malloc failed!!! ***\n"); exit(1); } if ((serv_s = malloc(NI_MAXSERV)) == NULL) { fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n"); exit(1); } error = getaddrinfo(remote_host, 0, NULL, &res); if (error) { printf("%s.\n", gai_strerror(error)); usage(argv[0]); exit(1); } switch (res->ai_family) { case AF_INET: t_addr = (struct sockaddr_in *)&s_rem; t_addr->sin_family = AF_INET; t_addr->sin_port = htons(remote_port); inet_pton(AF_INET, remote_host, &t_addr->sin_addr); r_len = sizeof (struct sockaddr_in); #ifdef __FreeBSD__ t_addr->sin_len = r_len; #endif break; case AF_INET6: t_addr6 = (struct sockaddr_in6 *)&s_rem; if (interface) t_addr6->sin6_scope_id = if_nametoindex(interface); t_addr6->sin6_family = AF_INET6; t_addr6->sin6_port = htons(remote_port); inet_pton(AF_INET6, remote_host, &t_addr6->sin6_addr); r_len = sizeof (struct sockaddr_in6); #ifdef __FreeBSD__ t_addr6->sin6_len = r_len; #endif break; } getnameinfo((struct sockaddr *)&s_rem, r_len, host_s, NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST); DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n", host_s, serv_s, res->ai_family); } if (local_host != NULL) { struct addrinfo *res; int error; char *host_s, *serv_s; struct sockaddr_in *t_addr; struct sockaddr_in6 *t_addr6; if ((host_s = malloc(NI_MAXHOST)) == NULL) { fprintf(stderr, "\n*** host_s malloc failed!!! ***\n"); exit(1); } if ((serv_s = malloc(NI_MAXSERV)) == NULL) { fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n"); exit(1); } if (strcmp(local_host, "0") == 0) local_host = "0.0.0.0"; error = getaddrinfo(local_host, 0, NULL, &res); if (error) { printf("%s.\n", gai_strerror(error)); usage(argv[0]); exit(1); } switch (res->ai_family) { case AF_INET: t_addr = (struct sockaddr_in *)&s_loc; t_addr->sin_family = AF_INET; t_addr->sin_port = htons(local_port); inet_pton(AF_INET, local_host, &t_addr->sin_addr); l_len = sizeof (struct sockaddr_in); #ifdef __FreeBSD__ t_addr->sin_len = l_len; #endif break; case AF_INET6: t_addr6 = (struct sockaddr_in6 *)&s_loc; if (interface) t_addr6->sin6_scope_id = if_nametoindex(interface); t_addr6->sin6_family = AF_INET6; t_addr6->sin6_port = htons(local_port); inet_pton(AF_INET6, local_host, &t_addr6->sin6_addr); l_len = sizeof (struct sockaddr_in6); #ifdef __FreeBSD__ t_addr6->sin6_len = l_len; #endif break; } error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s, NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST); if (error) printf("%s..\n", gai_strerror(error)); DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n", host_s, serv_s, res->ai_family); } /* Let the testing begin. */ start_test(role); return 0; } int bind_r(int sk, struct sockaddr_storage *saddr) { int error = 0, i = 0; char *host_s, *serv_s; if ((host_s = malloc(NI_MAXHOST)) == NULL) { fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n"); exit(1); } if ((serv_s = malloc(NI_MAXSERV)) == NULL) { fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n"); exit(1); } do { if (i > 0) sleep(1); /* sleep a while before new try... */ error = getnameinfo((struct sockaddr *)saddr, l_len, host_s, NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST); if (error) printf("%s\n", gai_strerror(error)); DEBUG_PRINT(DEBUG_MIN, "\tbind(sk=%d, [a:%s,p:%s]) -- attempt %d/%d\n", sk, host_s, serv_s, i+1, MAX_BIND_RETRYS); error = bind(sk, (struct sockaddr *)saddr, l_len); if (error != 0) { if( errno != EADDRINUSE ) { fprintf(stderr, "\n\n\t\t***bind: can " "not bind to %s:%s: %s ****\n", host_s, serv_s, strerror(errno)); exit(1); } } i++; if (i >= MAX_BIND_RETRYS) { fprintf(stderr, "Maximum bind() attempts. " "Die now...\n\n"); exit(1); } } while (error < 0 && i < MAX_BIND_RETRYS); return 0; } /* bind_r() */ int listen_r(int sk, int listen_count) { int error = 0; DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n", sk, listen_count); /* Mark sk as being able to accept new associations */ error = listen(sk, 1); if (error != 0) { fprintf(stderr, "\n\n\t\t*** listen: %s ***\n\n\n", strerror(errno)); exit(1); } return 0; } /* listen_r() */ int accept_r(int sk){ socklen_t len = 0; DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk); gsk = accept(sk, NULL, &len); if (gsk < 0) { fprintf(stderr, "\n\n\t\t*** accept: %s ***\n\n\n", strerror(errno)); exit(1); } return 0; } /* accept_r() */ int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) { int error = 0; DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk); /* Mark sk as being able to accept new associations */ error = connect(sk, serv_addr, addrlen); if (error != 0) { fprintf(stderr, "\n\n\t\t*** connect: %s ***\n\n\n", strerror(errno)); exit(1); } gsk = sk; return 0; } /* connect_r() */ int close_r(int sk) { int error = 0; DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk); error = close(sk); if (error != 0) { fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n", strerror(errno)); exit(1); } fflush(stdout); return 0; } /* close_r() */ int receive_r(int sk) { int error = 0; char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; struct iovec iov; struct msghdr inmessage; /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) { fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n"); exit(1); } iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); /* Get the messages sent */ while (1) { DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk); error = recvmsg(sk, &inmessage, MSG_WAITALL); if (error < 0 && error != EAGAIN) { fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n", strerror(errno)); fflush(stdout); close(sk); free(iov.iov_base); exit(1); } else if (error == 0) { printf("\n\t\trecvmsg() returned 0 !!!!\n"); fflush(stdout); } if(MSG_NOTIFICATION & inmessage.msg_flags) continue; /* got a notification... */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); iov.iov_len = REALLY_BIG; break; } free(iov.iov_base); return 0; } /* receive_r () */ void server(int sk) { int i; if (max_msgsize > DEFAULT_MAX_WINDOW) { if (setsockopt(sk, IPPROTO_SCTP, SO_RCVBUF, &max_msgsize, sizeof(max_msgsize)) < 0) { perror("setsockopt(SO_RCVBUF)"); exit(1); } } for (i = 0; i < msg_cnt; i++) { receive_r(sk); DEBUG_PRINT(DEBUG_MIN, "count %d\n", i+1); } } /* server() */ void * build_msg(int len) { int i = len - 1; int n; char *msg_buf, *p; msg_buf = malloc(len); if (NULL == msg_buf) { fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n"); exit(1); } p = msg_buf; do { n = ((i > 50)?50:i); memcpy(p, msg, ((i > 50)?50:i)); p += n; i -= n; } while (i > 0); msg_buf[len-1] = '\0'; return(msg_buf); } /* build_msg() */ int send_r(int sk, int stream, int order, int send_size, int assoc_i) { int error = 0; struct msghdr outmsg; struct iovec iov; char *message = NULL; int msglen = 0; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sinfo; if (send_size > 0) { message = build_msg(send_size); msglen = strlen(message) + 1; iov.iov_base = message; iov.iov_len = msglen; } else { exit(1); } outmsg.msg_name = &s_rem; outmsg.msg_namelen = sizeof(struct sockaddr_storage); outmsg.msg_iov = &iov; outmsg.msg_iovlen = 1; outmsg.msg_control = outcmsg; outmsg.msg_controllen = sizeof(outcmsg); outmsg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmsg); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmsg.msg_controllen = cmsg->cmsg_len; sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); sinfo->sinfo_ppid = rand(); sinfo->sinfo_stream = stream; sinfo->sinfo_flags = 0; if (!order) sinfo->sinfo_flags = SCTP_UNORDERED; DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n", sk, assoc_i, send_size); DEBUG_PRINT(DEBUG_MAX, "\t SNDRCV"); if (DEBUG_MAX == debug_level) { printf("(stream=%u ", sinfo->sinfo_stream); printf("flags=0x%x ", sinfo->sinfo_flags); printf("ppid=%u)\n", sinfo->sinfo_ppid); } /* Send to our neighbor. */ error = sendmsg(sk, &outmsg, MSG_WAITALL); if (error != msglen) { fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n", strerror(errno)); fflush(stdout); exit(1); } if (send_size > 0) free(message); return 0; } /* send_r() */ int next_order(int state, int pattern) { switch (pattern){ case ORDER_PATTERN_UNORDERED: state = 0; break; case ORDER_PATTERN_ORDERED: state = 1; break; case ORDER_PATTERN_ALTERNATE: state = state ? 0 : 1; break; case ORDER_PATTERN_RANDOM: state = rand() % 2; break; } return state; } int next_stream(int state, int pattern) { switch (pattern){ case STREAM_PATTERN_RANDOM: state = rand() % max_stream; break; case STREAM_PATTERN_SEQUENTIAL: state = state + 1; if (state >= max_stream) state = 0; break; } return state; } int next_msg_size(int msg_cnt) { int msg_size; if (size_arg) { msg_size = size_arg; } else { msg_size = (rand() % max_msgsize) + 1; } return msg_size; } /* next_msg_size() */ void client(int sk) { int msg_size; int i; for (i = 0; i < msg_cnt; i++) { msg_size = next_msg_size(i); order_state = next_order(order_state, order_pattern); stream_state = next_stream(stream_state, stream_pattern); if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) { close(sk); break; } /* The sender is echoing so do discard the echoed data. */ if (drain && ((i + 1) % period == 0)) { receive_r(sk); } } } /* client() */ void start_test(int role) { int sk, pid, ret; int i = 0; DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n"); repeat_count = repeat; DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_STREAM, IPPROTO_SCTP)"); if ((sk = socket(s_loc.ss_family, SOCK_STREAM, IPPROTO_SCTP)) < 0 ) { fprintf(stderr, "\n\n\t\t*** socket: failed to create" " socket: %s ***\n", strerror(errno)); exit(1); } DEBUG_PRINT(DEBUG_MIN, " -> sk=%d\n", sk); bind_r(sk, &s_loc); if (role == SERVER) { listen_r(sk, 1); accept_r(sk); } else { if (max_stream > 0) { struct sctp_initmsg initmsg; memset(&initmsg, 0, sizeof(initmsg)); initmsg.sinit_num_ostreams = max_stream; initmsg.sinit_max_instreams = max_stream; initmsg.sinit_max_attempts = 3; ret = setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg)); if (ret < 0) { perror("setsockopt(SCTP_INITMSG)"); exit(0); } } connect_r(sk, (struct sockaddr *)&s_rem, r_len); } if ((pid = fork()) == 0) { settimerhandle(); printstatus(gsk); while(1); } else { if (!debug_level) { printf(" "); } for(i = 0; i < repeat_count; i++) { if (role == SERVER) { DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.(%d/%d)\n", i+1, repeat_count); server(gsk); } else { DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n", i+1, repeat_count); client(sk); } fflush(stdout); } if (role == SERVER) close_r(gsk); close_r(sk); } } /* start_test() */ void settimerhandle(void) { struct sigaction act; struct itimerval interval; act.sa_handler = sighandler; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGPROF, &act, NULL); interval.it_value.tv_sec = DEFAULT_SEC; interval.it_value.tv_usec = DEFAULT_USEC; interval.it_interval = interval.it_value; setitimer(ITIMER_PROF, &interval, NULL); } void usage(char *argv0) { fprintf(stderr, "\nusage:\n"); fprintf(stderr, " server:\n"); fprintf(stderr, " %8s -H local-addr -P local-port -l [-d level] [-x]\n" "\t [-L num-ports] [-S num-ports]\n" "\t [-a assoc-pattern]\n" "\t [-i interface]\n" "\t [-f status-file]\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, " client:\n"); fprintf(stderr, " %8s -H local-addr -P local-port -h remote-addr\n" "\t -p remote-port -s [-c case ] [-d level]\n" "\t [-x repeat] [-o order-pattern] ream-pattern]\n" "\t [-M max-stream]\n" "\t [-m max-msgsize]\n" "\t [-L num-ports] [-S num-ports]\n" "\t [-i interface]\n" "\t [-f status-file]\n", argv0); fprintf(stderr, "\n"); fprintf(stderr, "\t-c value = Packets of specifed size.\n"); fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n"); fprintf(stderr, "\t-x number of repeats\n"); fprintf(stderr, "\t-X number of messages\n"); fprintf(stderr, "\t-o order-pattern\n"); fprintf(stderr, "\t 0 = all unordered(default) \n"); fprintf(stderr, "\t 1 = all ordered \n"); fprintf(stderr, "\t 2 = alternating \n"); fprintf(stderr, "\t 3 = random\n"); fprintf(stderr, "\t-M max-stream (default value 0)\n"); fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n"); fprintf(stderr, "\t-I receive after times of send, default value 1.\n"); fprintf(stderr, "\n"); fflush(stderr); } /* usage() */ void sighandler(int signo) { DEBUG_PRINT(DEBUG_MAX, "timeout sig\n"); printstatus(gsk); } char* get_sstat_state(int state) { switch(state) { case SCTP_EMPTY: return "EMPTY"; case SCTP_CLOSED: return "CLOSED"; case SCTP_COOKIE_WAIT: return "COOKIE_WAIT"; case SCTP_COOKIE_ECHOED: return "COOKIE_ECHOED"; case SCTP_ESTABLISHED: return "ESTABLISHED"; case SCTP_SHUTDOWN_PENDING: return "SHUTDOWN_PENDING"; case SCTP_SHUTDOWN_SENT: return "SHUTDOWN_SENT"; case SCTP_SHUTDOWN_RECEIVED: return "SHUTDOWN_RECEIVED"; case SCTP_SHUTDOWN_ACK_SENT: return "SHUTDOWN_ACK_SENT"; default: return "UNKNOW"; } } void printstatus(int sk) { static int cwnd = 0; static int count = 0; struct sctp_status status; socklen_t optlen; FILE * fp; const char *state_to_str[] = { [SCTP_INACTIVE] = "INACTIVE", [SCTP_PF] = "PF", [SCTP_ACTIVE] = "ACTIVE", [SCTP_UNCONFIRMED] = "UNCONFIRMED", }; optlen = sizeof(struct sctp_status); if(getsockopt(sk, IPPROTO_SCTP, SCTP_STATUS, &status, &optlen) < 0) { fprintf(stderr, "Error getting status: %s.\n", strerror(errno)); exit(1); } if (statusfile != NULL) { if (count == 0) unlink(statusfile); if((fp = fopen(statusfile, "a+")) == NULL) { perror("fopen"); exit(1); } } else fp = stdout; if (count == 0) fprintf(fp, "NO. ASSOC-ID STATE RWND UNACKDATA PENDDATA INSTRMS OUTSTRMS " "FRAG-POINT SPINFO-STATE SPINFO-CWDN SPINFO-SRTT SPINFO-RTO SPINFO-MTU\n"); if (cwnd != status.sstat_primary.spinfo_cwnd) { count++; fprintf(fp, "%-3d %-8d %-17s %-8d %-9d %-8d %-7d %-8d %-10d %-12s %-11d %-11d %-10d %d\n", count, status.sstat_assoc_id, get_sstat_state(status.sstat_state), status.sstat_rwnd, status.sstat_unackdata, status.sstat_penddata, status.sstat_instrms, status.sstat_outstrms, status.sstat_fragmentation_point, state_to_str[status.sstat_primary.spinfo_state], status.sstat_primary.spinfo_cwnd, status.sstat_primary.spinfo_srtt, status.sstat_primary.spinfo_rto, status.sstat_primary.spinfo_mtu); } cwnd = status.sstat_primary.spinfo_cwnd; fflush(fp); if (fp != stdout) fclose(fp); if (status.sstat_primary.spinfo_state != SCTP_ACTIVE) { close_r(sk); exit(1); } } lksctp-tools-1.0.16+dfsg.orig/src/apps/sctp_darn.h0000644000175000017500000000122312300634451021555 0ustar michaelmichael#ifndef __sctp_darn_h__ #define __sctp_darn_h__ #define REALLY_BIG 65536 #define SCTP_TESTPORT_1 1 #define SCTP_TESTPORT_2 2 void parse_arguments(int argc, char *argv[]); void usage(char *argv0); int command_listen(char *arg0, int sk); int command_send(char *arg0, int *skp); int command_poll(char *arg0); int test_print_message(int sk, struct msghdr *, size_t msg_len); typedef enum { COMMAND_NONE = 0, COMMAND_LISTEN, COMMAND_SEND, COMMAND_POLL, } command_t; typedef union { struct sockaddr_storage ss; struct sockaddr_in v4; struct sockaddr_in6 v6; struct sockaddr sa; } sockaddr_storage_t; #endif /* __sctp_darn_h__ */ lksctp-tools-1.0.16+dfsg.orig/src/apps/Makefile.am0000644000175000017500000000253612300634451021473 0ustar michaelmichael# Include these two in all the Makefile.am's!!! include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules include $(top_srcdir)/Makefile.dirs # General compilation flags AM_CPPFLAGS = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib \ -g -O2 -fno-strict-aliasing -Wall -Wstrict-prototypes \ -Wimplicit-function-declaration AM_LDFLAGS = LDADD = $(top_builddir)/src/testlib/libsctputil.la \ $(top_builddir)/src/lib/libsctp.la # programs to be installed with the distriubution bin_PROGRAMS = sctp_darn sctp_test sctp_status # Test programs and libraries to build noinst_PROGRAMS = bindx_test nagle_snd nagle_rcv myftp sctp_xconnect \ peel_server peel_client sctp_test sctp_status $(top_builddir)/src/lib/libsctp.la: $(MAKE) -C $(top_builddir)/src/lib libsctp.la $(top_builddir)/src/testlib/libsctputil.la: $(MAKE) -C $(top_builddir)/src/testlib libsctputil.la # Specifying the sources bindx_test_SOURCES = bindx_test.c sctp_darn_SOURCES = sctp_darn.c sctp_darn.h sctp_test_SOURCES = sctp_test.c sctp_status_SOURCES = sctp_status.c nagle_rcv_SOURCES = nagle_rcv.c nagle_snd_SOURCES = nagle_snd.c myftp_SOURCES = myftp.c sctp_xconnect_SOURCES = sctp_xconnect.c peel_server_SOURCES = peel_server.c peel_client_SOURCES = peel_client.c # Tutorials pkgdoc_DATA = sctp_darn.c sctp_darn.h sctp_test.c sctp_status.c lksctp-tools-1.0.16+dfsg.orig/src/apps/sctp_darn.c0000644000175000017500000016366112300634451021567 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2001, 2003 * Copyright (c) 1999 Cisco * Copyright (c) 1999, 2000, 2001 Motorola * Copyright (c) 2001 Nokia * Copyright (c) 2001 La Monte H.P. Yarroll * * 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 * * 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: * La Monte H.P. Yarroll * Karl Knutson * Hui Huang * Daisy Chang * Sridhar Samudrala */ /* This is a userspace test application for the SCTP kernel * implementation state machine. It is vaguely inspired by Stevens' * program "sock". * * It has the limited ability to send messages and to listen for messages * sent via SCTP. */ #include #include #include //#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sctp_darn.h" char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; #define GEN_DATA_FIRST 0x21 #define GEN_DATA_LAST 0x7e /* Display an IPv4 address in readable format. */ #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] /* Display an IPv6 address in readable format. */ #define NIP6(addr) \ ntohs((addr).s6_addr16[0]), \ ntohs((addr).s6_addr16[1]), \ ntohs((addr).s6_addr16[2]), \ ntohs((addr).s6_addr16[3]), \ ntohs((addr).s6_addr16[4]), \ ntohs((addr).s6_addr16[5]), \ ntohs((addr).s6_addr16[6]), \ ntohs((addr).s6_addr16[7]) /* These are the global options. */ char *local_host = NULL; int local_port = 0; char *remote_host = NULL; int remote_port = 0; command_t command = COMMAND_NONE; struct sockaddr *bindx_add_addrs = NULL; int bindx_add_count = 0; struct sockaddr *bindx_rem_addrs = NULL; int bindx_rem_count = 0; struct sockaddr *connectx_addrs = NULL; int connectx_count = 0; int interactive_mode = 0; int poll_skn = 0; int nonblocking = 0; int opt_space = 0; char gen_data = GEN_DATA_FIRST; char *inter_outbuf = NULL; int inter_outlen = 0; int inter_sk = 0; int poll_snd_size = 0; int use_poll = 0; int socket_type = SOCK_SEQPACKET; sctp_assoc_t associd = 0; int echo = 0; char *interface = "eth0"; int if_index = 0; sockaddr_storage_t remote_addr; sa_family_t ra_family; /* What family is remote_addr? */ int ra_len = 0; /* How long is remote_addr? */ void *ra_raw; /* This is the addr part of remote_addr. */ int new_connection = 1; enum inter_cmd_num { INTER_SND = 0, INTER_RCV, INTER_SNDBUF, INTER_RCVBUF, INTER_BINDX_ADD, INTER_BINDX_REM, INTER_SET_PRIM, INTER_SET_PEER_PRIM, INTER_SHUTDOWN, INTER_ABORT, INTER_NODELAY, INTER_MAXSEG, INTER_HEARTBEAT, INTER_GET_STATS }; enum shutdown_type { SHUTDOWN_ABORT = 0, SHUTDOWN_SHUTDOWN }; struct inter_entry { char *cmd; int cmd_num; }; struct inter_entry inter_commands[] = { {"snd", INTER_SND}, {"rcv", INTER_RCV}, {"sndbuf", INTER_SNDBUF}, {"rcvbuf", INTER_RCVBUF}, {"bindx-add", INTER_BINDX_ADD}, {"bindx-rem", INTER_BINDX_REM}, {"primary", INTER_SET_PRIM}, {"peer_primary", INTER_SET_PEER_PRIM}, {"shutdown", INTER_SHUTDOWN}, {"abort", INTER_ABORT}, {"nodelay", INTER_NODELAY}, {"maxseg", INTER_MAXSEG}, {"heartbeat", INTER_HEARTBEAT}, {"stats", INTER_GET_STATS}, {NULL, -1}, }; #define POLL_SK_MAX 256 /* The max number of sockets to select/poll. */ int poll_sks[POLL_SK_MAX]; /* The array for using select(). */ struct pollfd poll_fds[POLL_SK_MAX]; /* The array for using poll(). */ #define POLL_SND_SIZE 16384 /* Default message size in the poll mode. */ struct sockaddr *append_addr(const char *parm, struct sockaddr *addrs, int *ret_count) ; int build_endpoint(char *argv0, int portnum); static int parse_inter_commands(char *, char *, int); static void snd_func(char *); static void sndbuf_func(char *, int, int, int); static void rcvbuf_func(char *, int, int, int); static struct sockaddr *get_bindx_addr(char *, int *); static int bindx_func(char *, int, struct sockaddr *, int, int, int); static int connectx_func(char *, int, struct sockaddr *, int); static void primary_func(char *, int, char *, int); static void peer_primary_func(char *, int, char *, int); static void spp_hb_demand_func(char *, int, char *, int); static int nodelay_func(char *, int, int val, int set); static int maxseg_func(char *, int, int val, int set); static int shutdown_func(char *argv0, int *skp, int shutdown_type); static int get_assocstats_func(int, sctp_assoc_t); static int test_sk_for_assoc(int sk, sctp_assoc_t assoc_id); static char * gen_message(int); static sctp_assoc_t test_recv_assoc_change(int); static sctp_assoc_t test_verify_assoc_change(struct msghdr *); void print_addr_buf(void * laddrs, int n_laddrs); int print_sockaddr(struct sockaddr *sa_addr); int main(int argc, char *argv[]) { int sk = -1; int error = 0; int i; signal(SIGPIPE, SIG_IGN); parse_arguments(argc, argv); switch(command) { case COMMAND_NONE: fprintf(stderr, "%s: Please specify a command.\n", argv[0]); exit(1); break; case COMMAND_LISTEN: sk = build_endpoint(argv[0], local_port); error = command_listen(argv[0], sk); break; case COMMAND_SEND: sk = build_endpoint(argv[0], local_port); error = command_send(argv[0], &sk); break; case COMMAND_POLL: if (use_poll) { for (i = 0; i < poll_skn; i++) { poll_fds[i].fd = build_endpoint(argv[0], local_port + i); } } else { for (i = 0; i < poll_skn; i++) { poll_sks[i] = build_endpoint(argv[0], local_port + i); } } error = command_poll(argv[0]); break; default: fprintf(stderr, "%s: illegal command %d\n", argv[0], command); exit(1); } /* Shut down the link. */ if (COMMAND_POLL != command) { close(sk); } else { /* Shutdown all links. */ if (use_poll) { for (i = 0; i < poll_skn; i++) { close(poll_fds[i].fd); } } else { for (i = 0; i < poll_skn; i++) { close(poll_sks[i]); } } } exit(error); } /******************************************************************** * 2nd Level Abstractions ********************************************************************/ void parse_arguments(int argc, char *argv[]) { int option_index = 0; int c; struct sockaddr *tmp_addrs = NULL; static struct option long_options[] = { {"local", 1, 0, 1}, {"local-port", 1, 0, 2}, {"remote", 1, 0, 3}, {"remote-port", 1, 0, 4}, {"listen", 0, 0, 10}, {"send", 0, 0, 11}, {"bindx-add", 1, 0, 15}, {"bindx-rem", 1, 0, 16}, {"use-poll", 0, 0, 20}, {"echo", 0, 0, 'e'}, {"interface", optional_argument, 0, 5,}, {"connectx", 1, 0, 17}, {0, 0, 0, 0} }; /* Parse the arguments. */ while (1) { c = getopt_long (argc, argv, "B:H:IP:b:h:i:p:lm:nstz:ec:", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf("option %s", long_options[option_index].name); if (optarg) { printf(" with arg %s", optarg); } printf("\n"); break; case 1: /* local host */ case 'H': local_host = optarg; break; case 2: /* local port */ case 'P': local_port = atoi(optarg); break; case 3: /* remote host */ case 'h': remote_host = optarg; break; case 4: /* remote port */ case 'p': remote_port = atoi(optarg); break; case 5: /* interface for sin6_scope_id */ if (optarg) interface = optarg; if_index = if_nametoindex(interface); if (!if_index) { printf("Interface %s unknown\n", interface); exit(1); } break; /* COMMANDS */ case 10: /* listen */ case 'l': if (command) { fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]); exit(1); } else { command = COMMAND_LISTEN; } break; case 11: /* send */ case 's': if (command) { fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]); exit(1); } else { command = COMMAND_SEND; } break; case 15: /* bindx_add */ case 'B': tmp_addrs = append_addr(optarg, bindx_add_addrs, &bindx_add_count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, "%s\n", optarg); exit(2); } bindx_add_addrs = tmp_addrs; break; case 16: /* bindx_rem */ case 'b': tmp_addrs = append_addr(optarg, bindx_rem_addrs, &bindx_rem_count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, "%s\n", optarg); exit(2); } bindx_rem_addrs = tmp_addrs; break; case 17: /* connectx */ case 'c': tmp_addrs = append_addr(optarg, connectx_addrs, &connectx_count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, "%s\n", optarg); exit(2); } connectx_addrs = tmp_addrs; break; case 20: /* use-poll */ use_poll = 1; break; case 'I': interactive_mode = 1; break; case 'i': command = COMMAND_POLL; poll_skn = atoi(optarg); if (poll_skn <= 0 || poll_skn > POLL_SK_MAX) { fprintf(stderr, "Too many sockets for "); fprintf(stderr, "for polling\n"); exit(2); } break; case 'm': opt_space = atoi(optarg); break; case 'n': nonblocking = 1; break; case 't': socket_type = SOCK_STREAM; break; case 'z': poll_snd_size = atoi(optarg); if (poll_snd_size <= 0) { fprintf(stderr, "Bad message size.\n"); exit(2); } break; case 'e': echo = 1; break; case '?': usage(argv[0]); exit(1); default: printf ("%s: unrecognized option 0%c\n", argv[0], c); usage(argv[0]); exit(1); } } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf (stderr, "\n"); usage(argv[0]); exit(1); } if (NULL == local_host) { fprintf(stderr, "%s: You MUST provide a local host.\n", argv[0]); usage(argv[0]); exit(1); } if (command == COMMAND_SEND && NULL == remote_host && connectx_count == 0) { fprintf(stderr, "%s: You MUST provide a remote host for sending.\n", argv[0]); usage(argv[0]); exit(1); } if (remote_host != NULL && connectx_count != 0) { fprintf(stderr, "%s: You can not provide both -h and -c options.\n", argv[0]); usage(argv[0]); exit(1); } } /* parse_arguments() */ /* Set up the local endpoint. */ int build_endpoint(char *argv0, int portnum) { int retval; struct hostent *hst; sockaddr_storage_t local_addr; sa_family_t la_family; /* What family is local_addr? */ int la_len; /* How long is local_addr? */ void *la_raw; /* This is the addr part of local_addr. */ int error; struct sctp_event_subscribe subscribe; /* Get the transport address for the local host name. */ hst = gethostbyname(local_host); if (hst == NULL) { hst = gethostbyname2(local_host, AF_INET6); } if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host); exit(1); } la_family = hst->h_addrtype; switch (la_family) { case AF_INET: la_len = sizeof(local_addr.v4); la_raw = &local_addr.v4.sin_addr; local_addr.v4.sin_port = htons(portnum); local_addr.v4.sin_family = AF_INET; break; case AF_INET6: la_len = sizeof(local_addr.v6); la_raw = &local_addr.v6.sin6_addr; local_addr.v6.sin6_port = htons(portnum); local_addr.v6.sin6_family = AF_INET6; local_addr.v6.sin6_scope_id = if_index; break; default: fprintf(stderr, "Invalid address type.\n"); exit(1); break; } memcpy(la_raw, hst->h_addr_list[0], hst->h_length); /* Create the local endpoint. */ retval = socket(la_family, socket_type, IPPROTO_SCTP); if (retval < 0) { fprintf(stderr, "%s: failed to create socket: %s.\n", argv0, strerror(errno)); exit(1); } if (SOCK_SEQPACKET == socket_type) { memset(&subscribe, 0, sizeof(subscribe)); subscribe.sctp_data_io_event = 1; subscribe.sctp_association_event = 1; error = setsockopt(retval, SOL_SCTP, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)); if (error) { fprintf(stderr, "SCTP_EVENTS: error: %d\n", error); exit(1); } } /* Bind this socket to the test port. */ error = bind(retval, &local_addr.sa, la_len); if (error != 0) { fprintf(stderr, "%s: can not bind to %s:%d: %s.\n", argv0, local_host, portnum, strerror(errno)); exit(1); } /* Do we need to do bindx() to add any additional addresses? */ if (bindx_add_addrs) { if (0 != bindx_func(argv0, retval, bindx_add_addrs, bindx_add_count, SCTP_BINDX_ADD_ADDR, portnum)) { fprintf(stderr, "bindx_func (add) failed.\n"); exit(1); } } /* if (bindx_add_addrs) */ /* Do we need to do bindx() to remove any bound addresses? */ if (bindx_rem_addrs) { if (0 != bindx_func(argv0, retval, bindx_rem_addrs, bindx_rem_count, SCTP_BINDX_REM_ADDR, portnum)) { fprintf(stderr, "bindx_func (remove) failed.\n"); exit(1); } } /* if (bindx_rem_addrs) */ /* Do we want to run in the non-blocking mode? */ if (nonblocking) { error = fcntl(retval, F_SETFL, O_NONBLOCK); if (error != 0) { fprintf(stderr, "%s: error fcntl: %s.\n", argv0, strerror(errno)); exit(1); } } if (opt_space) { sndbuf_func(argv0, retval, opt_space, 1); rcvbuf_func(argv0, retval, opt_space, 1); } return retval; } /* build_endpoint() */ /* Convenience structure to determine space needed for cmsg. */ typedef union { struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcvinfo; } _sctp_cmsg_data_t; /* Listen on the socket, printing out anything that arrives. */ int command_listen(char *argv0, int sk) { char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; struct iovec iov; struct msghdr inmessage; sockaddr_storage_t msgname; char message[REALLY_BIG]; int done = 0; int error; int c; int recvsk = 0; /* Mark sk as being able to accept new associations */ error = listen(sk, 5); if (error != 0) { printf("\n\n\t\tlisten Failure: %s.\n\n\n", strerror(errno)); exit(1); } if (nonblocking) { if (!interactive_mode) { printf("Use -I for interactive mode with"); printf(" -n nonblocking\n"); exit(1); } } /* Initialize the global value for interactive mode functions. */ if (interactive_mode) { inter_sk = sk; } /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) { printf("%s: Can't allocate memory.\n", argv0); exit(1); } iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof(msgname); printf("%s listening...\n", argv0); /* Get the messages sent */ done = 0; while (!done) { if (interactive_mode) { /* Read from the user. */ if (remote_host) { printf("%s:%d-%s:%d Interactive mode> ", local_host, local_port, remote_host, remote_port); } else { printf("%s:%d-", local_host, local_port); if (associd) { print_sockaddr(&remote_addr.sa); } else { printf("?:%d", remote_port); } printf(" Interactive mode> "); } fflush(stdout); if (NULL == fgets(message, REALLY_BIG, stdin)) { done = 1; continue; } if (0 <= (c = parse_inter_commands(argv0, message, 0))) { if (INTER_RCV != c) { continue; } } else { continue; } } if (socket_type == SOCK_STREAM) { socklen_t len = 0; if (!recvsk) { if ((recvsk = accept(sk, NULL, &len)) < 0) { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); exit(1); } } } else { recvsk = sk; } error = recvmsg(recvsk, &inmessage, MSG_WAITALL); if (error < 0) { if (nonblocking && (EAGAIN == errno)) { error = 0; continue; } if (socket_type == SOCK_STREAM) { if (ENOTCONN != errno) break; printf("No association is present now!!\n"); close(recvsk); recvsk = 0; continue; } break; } /* Update the associd when a notification is received on a * UDP-style socket. */ if (inmessage.msg_flags & MSG_NOTIFICATION) associd = test_verify_assoc_change(&inmessage); if (echo) { if( !(MSG_NOTIFICATION & inmessage.msg_flags)) { sendto(recvsk, inmessage.msg_iov->iov_base, error, 0, (struct sockaddr *)&msgname, sizeof(msgname)); } } test_print_message(sk, &inmessage, error); inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_name = &msgname; inmessage.msg_namelen = sizeof(msgname); iov.iov_len = REALLY_BIG; /* Verify that the association is no longer present. */ if (0 != test_sk_for_assoc(recvsk, associd)) { printf("No association is present now!!\n"); if (socket_type == SOCK_STREAM) { close(recvsk); recvsk = 0; } } } if (error < 0) { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); exit(1); } return error; } /* command_listen() */ /* Read lines from stdin and send them to the socket. */ int command_send(char *argv0, int *skp) { struct msghdr outmsg; struct iovec iov; int done = 0; char message[REALLY_BIG]; struct hostent *hst; int c; struct sockaddr *addrs; int msglen; int error = 0; int sk = *skp; /* Set up the destination. */ if (remote_host != NULL) { hst = gethostbyname(remote_host); if (hst == NULL) { hst = gethostbyname2(remote_host, AF_INET6); } if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, remote_host); exit(1); } ra_family = hst->h_addrtype; switch (ra_family) { case AF_INET: ra_len = sizeof(remote_addr.v4); ra_raw = &remote_addr.v4.sin_addr; remote_addr.v4.sin_port = htons(remote_port); remote_addr.v4.sin_family = AF_INET; break; case AF_INET6: ra_len = sizeof(remote_addr.v6); ra_raw = &remote_addr.v6.sin6_addr; remote_addr.v6.sin6_port = htons(remote_port); remote_addr.v6.sin6_family = AF_INET6; remote_addr.v6.sin6_scope_id = if_index; break; default: fprintf(stderr, "Invalid address type.\n"); exit(1); break; } memcpy(ra_raw, hst->h_addr_list[0], hst->h_length); } /* Initialize the global value for interactive mode functions. */ if (interactive_mode) { inter_sk = sk; } printf("%s ready to send...\n", argv0); while (!done) { /* Read from the user. */ if (remote_host) { if (interactive_mode) { printf("%s:%d-%s:%d Interactive mode> ", local_host, local_port, remote_host, remote_port); } else { printf("%s:%d-%s:%d> ", local_host, local_port, remote_host, remote_port); } } else { printf("%s:%d-", local_host, local_port); if (associd) { print_sockaddr(&remote_addr.sa); } else { printf("XXXXXX:%d", remote_port); } if (interactive_mode) { printf(" Interactive mode> "); } else { printf("> "); } } fflush(stdout); if (NULL == fgets(message, REALLY_BIG, stdin)) { done = 1; continue; } if (interactive_mode) { /* This is the send only agent. */ if (0 <= (c = parse_inter_commands(argv0, message, 1))) { if (INTER_SND == c) { iov.iov_base = inter_outbuf; msglen = inter_outlen; iov.iov_len = msglen; } else { continue; } } else { continue; } } else { /* Send to our neighbor. */ msglen = strlen(message) + 1; iov.iov_len = msglen; } /* For a UDP-style socket, verify if an existing association * has gone. If so, receive the pending SCTP_ASSOC_CHANGE * notification. */ if ((SOCK_SEQPACKET == socket_type) && associd && (0 != test_sk_for_assoc(sk, associd))) { associd = test_recv_assoc_change(sk); printf("Old association gone, Starting a new one!\n"); new_connection = 1; } if (new_connection && connectx_count != 0) { /* Do a sctp_connectx() to establish a connection. */ error = connectx_func(argv0, sk, connectx_addrs, connectx_count); if (0 != error) { if (error == -2) { printf("Connection refused\n"); if (SOCK_SEQPACKET == socket_type) { associd = test_recv_assoc_change(sk); } continue; } fprintf(stderr, "connectx failed.\n"); exit(1); } if (SOCK_SEQPACKET == socket_type) { associd = test_recv_assoc_change(sk); } else { associd = 1; } int rc = sctp_getpaddrs(sk, associd, &addrs); if (0 >= rc) { if (rc == 0) { fprintf(stderr, "sctp_getpaddrs failed, no peers.\n"); } else { fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno); } exit(1); } printf("New connection, peer addresses\n"); print_addr_buf(addrs, rc); ra_family = addrs[0].sa_family; switch (ra_family) { case AF_INET: ra_len = sizeof(remote_addr.v4); break; case AF_INET6: ra_len = sizeof(remote_addr.v6); break; default: fprintf(stderr, "Invalid address type.\n"); exit(1); } memcpy(&remote_addr, &addrs[0], ra_len); sctp_freepaddrs(addrs); new_connection = 0; } do { if (SOCK_SEQPACKET == socket_type || (connectx_count == 0 && new_connection)) { /* Initialize the message struct we use to pass * messages to the remote socket. */ if (!interactive_mode) { iov.iov_base = message; iov.iov_len = msglen; } outmsg.msg_iov = &iov; outmsg.msg_iovlen = 1; outmsg.msg_control = NULL; outmsg.msg_controllen = 0; outmsg.msg_name = &remote_addr; outmsg.msg_namelen = ra_len; error = sendmsg(sk, &outmsg, 0); } else { error = send(sk, message, msglen, 0); if (error == -1 && errno == EPIPE) { error = close(sk); if (error != 0) { fprintf(stderr, "close failed %s\n", strerror(errno)); exit(1); } *skp = sk = build_endpoint(argv0, local_port); break; } } if (error != msglen) { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); if (nonblocking && EAGAIN == errno) { if (interactive_mode) { break; } continue; } exit(1); } else { break; } } while (error != msglen); /* If this is the first message sent over a UDP-style socket, * get the associd from the SCTP_ASSOC_CHANGE notification. */ if ((SOCK_SEQPACKET == socket_type) && (0 == associd)) associd = test_recv_assoc_change(sk); /* Verify there is no association. */ if (0 != test_sk_for_assoc(sk, associd)) { printf("No association is present now!!\n"); new_connection = 1; } else { if (new_connection) { int rc = sctp_getpaddrs(sk, associd, &addrs); if (0 >= rc) { if (rc == 0) { fprintf(stderr, "sctp_getpaddrs failed, no peers.\n"); } else { fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno); } exit(1); } printf("New connection, peer addresses\n"); print_addr_buf(addrs, rc); sctp_freepaddrs(addrs); new_connection = 0; } } /* Clean up. */ if (interactive_mode) { free(inter_outbuf); inter_outbuf = NULL; } } /* while(!done) */ return error; } /* command_send() */ /* Listen on the array of sockets, printing out anything that arrives. */ int command_poll(char *argv0) { char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; struct iovec iov; struct msghdr inmessage; int done = 0; int error = 0; int max_fd, i, ret; int size; fd_set *ibitsp = NULL; fd_set *obitsp = NULL; fd_set *xbitsp = NULL; struct msghdr outmsg; struct hostent *hst; int msglen; int temp_fd, temp_set; /* If a remote host is specified, initialize the destination. */ if (remote_host) { /* Set up the destination. */ hst = gethostbyname(remote_host); if (hst == NULL) { hst = gethostbyname2(remote_host, AF_INET6); } if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, remote_host); exit(1); } ra_family = hst->h_addrtype; switch (ra_family) { case AF_INET: ra_len = sizeof(remote_addr.v4); ra_raw = &remote_addr.v4.sin_addr; remote_addr.v4.sin_port = htons(remote_port); remote_addr.v4.sin_family = AF_INET; break; case AF_INET6: ra_len = sizeof(remote_addr.v6); ra_raw = &remote_addr.v6.sin6_addr; remote_addr.v6.sin6_port = htons(remote_port); remote_addr.v6.sin6_family = AF_INET6; remote_addr.v6.sin6_scope_id = if_index; break; default: fprintf(stderr, "Invalid address type.\n"); exit(1); break; } memcpy(ra_raw, hst->h_addr_list[0], hst->h_length); /* Initialize the message struct we use to pass messages to * the remote socket. */ outmsg.msg_iov = &iov; outmsg.msg_iovlen = 1; outmsg.msg_control = NULL; outmsg.msg_controllen = 0; outmsg.msg_name = &remote_addr; outmsg.msg_namelen = ra_len; } max_fd = -1; /* Set all of the sockets to be ready for listening. */ if (use_poll) { for (i = 0; i < poll_skn; i++) { error = listen(poll_fds[i].fd, 1); if (error != 0) { printf("%s: Listen failed on socket number ", argv0); printf("%d: %s.\n", i, strerror(errno)); exit(1); } } printf("%s listening...\n", argv0); } else { for (i = 0; i < poll_skn; i++) { error = listen(poll_sks[i], 1); if (error != 0) { printf("%s: Listen failed on socket number ", argv0); printf("%d: %s.\n", i, strerror(errno)); exit(1); } if (poll_sks[i] > max_fd) { max_fd = poll_sks[i]; } } printf("%s listening...\n", argv0); size = howmany(max_fd + 1, NFDBITS) * sizeof(fd_mask); if ((ibitsp = (fd_set *)malloc(size)) == NULL) { printf("%s: Can't allocate memory.\n", argv0); exit(1); } if ((obitsp = (fd_set *)malloc(size)) == NULL) { printf("%s: Can't allocate memory.\n", argv0); exit(1); } if ((xbitsp = (fd_set *)malloc(size)) == NULL) { printf("%s: Can't allocate memory.\n", argv0); exit(1); } memset(ibitsp, 0, size); memset(obitsp, 0, size); memset(xbitsp, 0, size); } /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) { printf("%s: Can't allocate memory.\n", argv0); exit(1); } iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); done = 0; /* Set the default send message size. */ if (!poll_snd_size) { poll_snd_size = POLL_SND_SIZE; } while (!done) { if (use_poll) { for (i = 0; i < poll_skn; i++) { poll_fds[i].events = POLLIN; } if (remote_host) { /* Poll output on the first socket. */ poll_fds[0].events |= POLLOUT; } if ((ret = poll(poll_fds, poll_skn, -1))) { if (ret == -1) { break; } } } else { for (i = 0; i < poll_skn; i++) { FD_SET(poll_sks[i], ibitsp); FD_SET(poll_sks[i], xbitsp); } if (remote_host) { /* Only select output on the first socket. */ FD_SET(poll_sks[0], obitsp); } if ((ret = select(max_fd + 1, ibitsp, obitsp, xbitsp, (struct timeval *)0)) < 0) { if (ret == -1) { break; } } } if (remote_host) { if (use_poll) { temp_set = poll_fds[0].revents & POLLOUT; temp_fd = poll_fds[0].fd; } else { temp_set = FD_ISSET(poll_sks[0], obitsp); temp_fd = poll_sks[0]; } if (temp_set) { inter_outbuf = gen_message(poll_snd_size); if (!inter_outbuf) { fprintf(stderr, "Cannot allocate out message.\n"); exit(1); } iov.iov_base = inter_outbuf; msglen = poll_snd_size; iov.iov_len = msglen; error = sendmsg(temp_fd, &outmsg, 0); fprintf(stderr, "sent a message, msglen = %d\n", msglen); if (error != msglen) { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); if ((!nonblocking) || (EAGAIN != errno)) { exit(1); } } /* Clean up. */ free(inter_outbuf); inter_outbuf = NULL; } } /* while(!done) */ for (i = 0; !done && (i < poll_skn); i++) { if (use_poll) { temp_set = poll_fds[i].revents & POLLIN; temp_fd = poll_fds[i].fd; } else { temp_set = FD_ISSET(poll_sks[i], ibitsp); temp_fd = poll_sks[i]; } if (temp_set) { error = recvmsg(temp_fd, &inmessage, MSG_WAITALL); if (error < 0) { if ((EAGAIN == errno)) { error = 0; continue; } else { fprintf(stderr, "%s: error: %s.\n", argv0, strerror(errno)); exit(1); } } test_print_message(temp_fd, &inmessage, error); inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); iov.iov_len = REALLY_BIG; } /* Update the associd when a notification is received * on a UDP-style socket. */ if (inmessage.msg_flags & MSG_NOTIFICATION) associd = test_verify_assoc_change(&inmessage); /* Verify there is no association. */ if (0 != test_sk_for_assoc(poll_sks[i], associd)) { printf("No association is present in sk " "No.%d now!!\n",i); } } } if (!use_poll) { free(ibitsp); free(obitsp); free(xbitsp); } return error; } /* command_poll() */ /******************************************************************** * 3rd Level Abstractions ********************************************************************/ #define FPS(arg) fprintf(stderr, arg) void usage(char *argv0) { /* * The bindx options, --bindx-add and --bindx-rem, are added to * * 1. provide first testcases for the new bindx system call * * 2. continue to grow sctp_darn with more functions and * features so it will be equivalent to the "sock" tool for * TCP as for SCTP. * * FIXME - * * It is not very effective to use these two options in the * current command line mode of sctp_darn. For example, the * --bindx-rem option can only be used in conjunction with the * --bindx-add simply to test the function in the kernel * path. Ideally, bindx needs to be tested by a tool which * provides an interactive mode for users to change parameters * and configuration dynamically with existing endpoints and * associations. */ fprintf(stderr, "Usage: %s -H -P " "[-h ] [-p ] -l|s\n" " -H, --local\t\tspecify one of the local addresses,\n" " -P, --local-port\tspecify the port number for local addresses,\n" " -h, --remote\t\tspecify the peer address,\n" " -p, --remote-port\tspecify the port number for the peer address,\n" " -l, --listen\t\tprint messages received from the peer,\n" " -s, --send\t\tsend messages to the peer,\n" " -B, --bindx-add" "\tadd the specified address(es) as additional bind\n" "\t\t\taddresses to the local socket. Multiple addresses can\n" "\t\t\tbe specified by using this argument multiple times.\n" "\t\t\tFor example, '-B 10.0.0.1 -B 20.0.0.2'.\n" " -b, --bindx-rem" "\tremove the specified address(es) from the bind\n" "\t\t\taddresses of the local socket. Multiple addresses can\n" "\t\t\tbe specified by using this argument multiple times.\n" "\t\t\tFor example, '-b 10.0.0.1 -b 20.0.0.2'.\n" " -c, --connectx" "\t\tuse the specified address(es) for connection to the\n" "\t\t\tpeer socket. Multiple addresses can be specified by\n" "\t\t\tusing this argument multiple times.\n" "\t\t\tFor example, '-c 10.0.0.1 -c 20.0.0.2'.\n" "\t\t\tThis option is incompatible with the -h option.\n" " -I\t\t\tuse the interactive mode.\n" " -i\t\t\tsetup the specified number of endpoints by using the\n" "\t\t\tspecified local host (-H) and local port (-P). The port\n" "\t\t\tnumber will be incremented by one for each additional\n" "\t\t\tendpoint. All of these endpoints will be listening.\n" "\t\t\tIf a remote host (-h) and a remote port are also\n" "\t\t\tspecified, the first endpoint will start sending fixed\n" "\t\t\tsized messages to the remote host.\n" " -m\t\t\tspecify the sockopt sndbuf/rcvbuf size.\n" " -n\t\t\tset the socket(s) to be in the non-blocking mode.\n" "\t\t\tcollect messages from stdin and deliver them to the\n" "\t\t\tpeer,\n" "--use-poll\t\tuse system call poll() for polling among the\n" "\t\t\tnumber of endpoints specified by the -i option. Without\n" "\t\t\tthis option, select() would be used as default.\n" " -t\t\t\tuse SOCK_STREAM tcp-style sockets.\n" " -z\t\t\tspecify the message size to be sent. The default\n" "\t\t\tmessage size generated would be 16K.\n" " --interface=\"ifname\"\tselect interface for sin6_scope_id.\n", argv0); } /* This function checks messages to see if they are of type 'event' * and if they are well-formed. */ int user_test_check_message(struct msghdr *msg, int controllen, sctp_cmsg_t event) { if (msg->msg_controllen != controllen) { fprintf(stderr, "Got control structure of length %zu, not %d\n", msg->msg_controllen, controllen); exit(1); } if (controllen > 0 && event != CMSG_FIRSTHDR(msg)->cmsg_type) { fprintf(stderr, "Wrong kind of event: %d, not %d\n", CMSG_FIRSTHDR(msg)->cmsg_type, event); exit(1); } return 1; } /* user_test_check_message() */ /* Add another address represented as the string 'parm' to the list * addrs. The argument count is the number of addrs on input and is * adjusted for output. */ struct sockaddr * append_addr(const char *parm, struct sockaddr *addrs, int *ret_count) { struct sockaddr *new_addrs = NULL; void *aptr; struct sockaddr *sa_addr; struct sockaddr_in *b4ap; struct sockaddr_in6 *b6ap; struct hostent *hst4 = NULL; struct hostent *hst6 = NULL; int i4 = 0; int i6 = 0; int j; int orig_count = *ret_count; int count = orig_count; /* Get the entries for this host. */ hst4 = gethostbyname(parm); hst6 = gethostbyname2(parm, AF_INET6); if ((NULL == hst4 || hst4->h_length < 1) && (NULL == hst6 || hst6->h_length < 1)) { fprintf(stderr, "bad hostname: %s\n", parm); goto finally; } /* Figure out the number of addresses. */ if (NULL != hst4) { for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) { count++; } } if (NULL != hst6) { for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) { count++; } } /* Expand memory for the new addresses. Assume all the addresses * are v6 addresses. */ new_addrs = (struct sockaddr *) realloc(addrs, sizeof(struct sockaddr_in6) * count); if (NULL == new_addrs) { count = *ret_count; goto finally; } /* Skip the existing addresses. */ aptr = new_addrs; for (j = 0; j < orig_count; j++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: aptr += sizeof(struct sockaddr_in); break; case AF_INET6: aptr += sizeof(struct sockaddr_in6); break; default: count = orig_count; goto finally; } } /* Put the new addresses away. */ if (NULL != hst4) { for (j = 0; j < i4; ++j) { b4ap = (struct sockaddr_in *)aptr; memset(b4ap, 0x00, sizeof(*b4ap)); b4ap->sin_family = AF_INET; b4ap->sin_port = htons(local_port); bcopy(hst4->h_addr_list[j], &b4ap->sin_addr, hst4->h_length); aptr += sizeof(struct sockaddr_in); } /* for (loop through the new v4 addresses) */ } if (NULL != hst6) { for (j = 0; j < i6; ++j) { b6ap = (struct sockaddr_in6 *)aptr; memset(b6ap, 0x00, sizeof(*b6ap)); b6ap->sin6_family = AF_INET6; b6ap->sin6_port = htons(local_port); b6ap->sin6_scope_id = if_index; bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr, hst6->h_length); aptr += sizeof(struct sockaddr_in6); } /* for (loop through the new v6 addresses) */ } finally: *ret_count = count; return new_addrs; } /* append_addr() */ static int parse_inter_commands(char *argv0, char *input, int snd_only) { int i; char *p; int len; int set = 0; int val; struct sockaddr *tmp_addrs = NULL; p = input; if (*p == '?' || *p == '\n') { printf("Interactive commands:\n"); printf("snd= - Do a sendmsg with the specified"); printf(" length.\n"); printf("rcv= - Do a recvmsg."); printf("The length is ignored for now.\n"); printf("bindx-add= - Add a local address"); printf(" with bindx. \n"); printf("bindx-rem= - Remove a local address"); printf(" with bindx. \n"); printf("rcvbuf= - Get/Set receive buffer size\n"); printf("sndbuf= - Get/Set send buffer size.\n"); printf("primary= - Get/Set association's primary\n"); printf("peer_primary=addr- Set association's peer_primary\n"); printf("heartbeat= - Request a user initiated heartbeat\n"); printf("maxseg= - Get/Set Maximum fragment size.\n"); printf("nodelay=<0|1> - Get/Set NODELAY option.\n"); printf("shutdown - Shutdown the association.\n"); printf("abort - Abort the association.\n"); printf("stats - Print GET_ASSOC_STATS (if available in kernel).\n"); printf("? - Help. Display this message.\n"); return -1; } for (i = 0; i < REALLY_BIG; i++) { if (('=' == *p) || ('?' == *p) || ('\n' == *p)) { if ('=' == *p) { set = 1; } *p++ = '\0'; break; } p++; } if (i >= REALLY_BIG) { printf("Invalid input.\n"); return -1; } i = 0; while (NULL != inter_commands[i].cmd) { if (!strcmp(input, inter_commands[i].cmd)) { switch (i) { case INTER_SND: if (snd_only) { if (*p < '0' || *p > '9') { goto err_input; } snd_func(p); } else { goto err_input; } break; case INTER_RCV: if (snd_only) { goto err_input; } break; case INTER_SNDBUF: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } len = (set) ? atoi(p) : 0; sndbuf_func(argv0, inter_sk, len, set); break; case INTER_RCVBUF: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } len = (set) ? atoi(p) : 0; rcvbuf_func(argv0, inter_sk, len, set); break; case INTER_BINDX_ADD: tmp_addrs = get_bindx_addr(p, &len); bindx_func(argv0, inter_sk, tmp_addrs, len, SCTP_BINDX_ADD_ADDR, local_port); free(tmp_addrs); break; case INTER_BINDX_REM: tmp_addrs = get_bindx_addr(p, &len); bindx_func(argv0, inter_sk, tmp_addrs, len, SCTP_BINDX_REM_ADDR, local_port); free(tmp_addrs); break; case INTER_SET_PRIM: primary_func(argv0, inter_sk, p, set); break; case INTER_SET_PEER_PRIM: peer_primary_func(argv0, inter_sk, p, set); break; case INTER_HEARTBEAT: spp_hb_demand_func(argv0, inter_sk, p, set); break; case INTER_SHUTDOWN: shutdown_func(argv0, &inter_sk, SHUTDOWN_SHUTDOWN); break; case INTER_ABORT: shutdown_func(argv0, &inter_sk, SHUTDOWN_ABORT); break; case INTER_NODELAY: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } val = (set) ? atoi(p) : 0; nodelay_func(argv0, inter_sk, val, set); break; case INTER_MAXSEG: if (set) { if (*p < '0' || *p > '9') { goto err_input; } } val = (set) ? atoi(p) : 0; maxseg_func(argv0, inter_sk, val, set); break; case INTER_GET_STATS: get_assocstats_func(inter_sk, associd); break; default: goto err_input; break; } return i; } i++; } err_input: printf("Invalid input.\n"); return -1; } /* parse_inter_commands() */ static char * gen_message(int len) { char *buf; char *p; int i; buf = malloc(len); if (NULL != buf) { for (i = 0, p = buf; i < len; i++, p++) { if (gen_data > GEN_DATA_LAST) { gen_data = GEN_DATA_FIRST; } *p = gen_data++; } } return(buf); } /* gen_message() */ static void snd_func(char *input) { int len; len = atoi(input); if (!(inter_outbuf = gen_message(len))) { fprintf(stderr, "Cannot allocate out message.\n"); exit(1); } inter_outlen = len; } /* snd_func() */ static void sndbuf_func(char *argv0, int sk, int len, int set) { int error; socklen_t optlen; if (set) { error = setsockopt(sk, SOL_SOCKET, SO_SNDBUF, (char *)&len, sizeof(len)); } else { optlen = sizeof(len); error = getsockopt(sk, SOL_SOCKET, SO_SNDBUF, (char *)&len, &optlen); } if (error != 0) { fprintf(stderr, "%s: Error setting/getting sndbuf: %s.\n", argv0, strerror(errno)); exit(1); } if (!set) { printf("sndbuf is %d.\n", len); } } /* sndbuf_func() */ static void rcvbuf_func(char *argv0, int sk, int len, int set) { int error; socklen_t optlen; if (set) { error = setsockopt(sk, SOL_SOCKET, SO_RCVBUF, (char *)&len, sizeof(len)); } else { optlen = sizeof(len); error = getsockopt(sk, SOL_SOCKET, SO_RCVBUF, (char *)&len, &optlen); } if (error != 0) { fprintf(stderr, "%s: Error setting/getting rcvbuf: %s.\n", argv0, strerror(errno)); exit(1); } if (!set) { printf("rcvbuf is %d.\n", len); } } /* rcvbuf_func() */ static struct sockaddr * get_bindx_addr(char *in, int *count) { struct sockaddr *tmp_addrs = NULL; char *p = in; /* Set the buffer for address parsing. */ while ('\n' != *p) { p++; } *p = '\0'; *count = 0; tmp_addrs = append_addr(in, tmp_addrs, count); if (NULL == tmp_addrs) { /* We have no memory, so keep fprintf() * from trying to allocate more. */ fprintf(stderr, "No memory to add "); fprintf(stderr, "%s\n", in); exit(2); } return tmp_addrs; } /* get_bindx_addr() */ static int bindx_func(char *argv0, int sk, struct sockaddr *addrs, int count, int flag, int portnum) { int error; int i; struct sockaddr *sa_addr; void *aptr; if (0 == portnum) { fprintf(stderr, "%s: A non-0 local port number is ", argv0); fprintf(stderr, "required for bindx to work!\n"); return -1 ; } /* Set the port in every address. */ aptr = addrs; for (i = 0; i < count; i++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: ((struct sockaddr_in *)sa_addr)->sin_port = htons(portnum); aptr += sizeof(struct sockaddr_in); break; case AF_INET6: ((struct sockaddr_in6 *)sa_addr)->sin6_port = htons(portnum); aptr += sizeof(struct sockaddr_in6); break; default: fprintf(stderr, "Invalid address family\n"); return -1; } } error = sctp_bindx(sk, addrs, count, flag); if (error != 0) { if (flag == SCTP_BINDX_ADD_ADDR) { fprintf(stderr, "%s: error adding addrs: %s.\n", argv0, strerror(errno)); return -1; } else { fprintf(stderr, "%s: error removing addrs: %s.\n", argv0, strerror(errno)); return -1; } } return 0; } /* bindx_func() */ static int connectx_func(char *argv0, int sk, struct sockaddr *addrs, int count) { int error; int i; struct sockaddr *sa_addr; void *aptr; if (0 == remote_port) { fprintf(stderr, "%s: A non-0 remote port number is ", argv0); fprintf(stderr, "required for connectx to work!\n"); return -1 ; } /* Set the port in every address. */ aptr = addrs; for (i = 0; i < count; i++) { sa_addr = (struct sockaddr *)aptr; switch(sa_addr->sa_family) { case AF_INET: ((struct sockaddr_in *)sa_addr)->sin_port = htons(remote_port); aptr += sizeof(struct sockaddr_in); break; case AF_INET6: ((struct sockaddr_in6 *)sa_addr)->sin6_port = htons(remote_port); aptr += sizeof(struct sockaddr_in6); break; default: fprintf(stderr, "Invalid address family\n"); return -1; } } error = sctp_connectx(sk, addrs, count, NULL); if (error != 0) { if (errno == ECONNREFUSED) return -2; fprintf(stderr, "%s: error connecting to addrs: %s.\n", argv0, strerror(errno)); return -1; } return 0; } /* connectx_func() */ static void primary_func(char *argv0, int sk, char *cp, int set) { struct sctp_prim prim; struct sockaddr_in *in_addr; struct sockaddr_in6 *in6_addr; struct sockaddr *saddr; socklen_t prim_len; int ret; char *p = cp; char addr_buf[INET6_ADDRSTRLEN]; const char *ap = NULL; prim_len = sizeof(struct sctp_prim); if (!set) { prim.ssp_assoc_id = associd; ret = getsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len); if (ret < 0) goto err; saddr = (struct sockaddr *)&prim.ssp_addr; if (AF_INET == saddr->sa_family) { in_addr = (struct sockaddr_in *)&prim.ssp_addr; ap = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf, INET6_ADDRSTRLEN); } else if (AF_INET6 == saddr->sa_family) { in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr; ap = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf, INET6_ADDRSTRLEN); } if (!ap) goto err; printf("%s\n", ap); return; } /* Set the buffer for address parsing. */ while ('\n' != *p) p++; *p = '\0'; prim.ssp_assoc_id = associd; if (strchr(cp, '.')) { in_addr = (struct sockaddr_in *)&prim.ssp_addr; in_addr->sin_port = htons(remote_port); in_addr->sin_family = AF_INET; ret = inet_pton (AF_INET, cp, &in_addr->sin_addr); if (ret <= 0) goto err; } else if (strchr(cp, ':')) { in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr; in6_addr->sin6_port = htons(remote_port); in6_addr->sin6_family = AF_INET6; ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr); if (ret <= 0) goto err; } else goto err; ret = setsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(struct sctp_prim)); if (ret < 0) goto err; return; err: if (!errno) errno = EINVAL; fprintf(stderr, "%s: error %s primary: %s.\n", argv0, (set)?"setting":"getting", strerror(errno)); } static void peer_primary_func(char *argv0, int sk, char *cp, int set) { struct sctp_setpeerprim setpeerprim; struct sockaddr_in *in_addr; struct sockaddr_in6 *in6_addr; int ret; char *p = cp; if (!set) { goto err; } /* Set the buffer for address parsing. */ while ('\n' != *p) p++; *p = '\0'; setpeerprim.sspp_assoc_id = associd; if (strchr(cp, '.')) { in_addr = (struct sockaddr_in *)&setpeerprim.sspp_addr; in_addr->sin_port = htons(local_port); in_addr->sin_family = AF_INET; ret = inet_pton (AF_INET, cp, &in_addr->sin_addr); if (ret <= 0) goto err; } else if (strchr(cp, ':')) { in6_addr = (struct sockaddr_in6 *)&setpeerprim.sspp_addr; in6_addr->sin6_port = htons(local_port); in6_addr->sin6_family = AF_INET6; ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr); if (ret <= 0) goto err; } else goto err; ret = setsockopt(sk, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &setpeerprim, sizeof(struct sctp_setpeerprim)); if (ret < 0) goto err; return; err: if (!errno) errno = EINVAL; fprintf(stderr, "%s: error %s peer_primary: %s.\n", argv0, (set)?"setting":"getting", strerror(errno)); } static void spp_hb_demand_func(char *argv0, int sk, char *cp, int set) { struct sctp_paddrparams params; struct sockaddr_in *in_addr; struct sockaddr_in6 *in6_addr; int ret; char *p = cp; memset(¶ms, 0, sizeof(struct sctp_paddrparams)); params.spp_assoc_id = associd; params.spp_flags = SPP_HB_DEMAND; if (set) { /* Set the buffer for address parsing. */ while ('\n' != *p) p++; *p = '\0'; if (strchr(cp, '.')) { in_addr = (struct sockaddr_in *)¶ms.spp_address; in_addr->sin_port = htons(remote_port); in_addr->sin_family = AF_INET; ret = inet_pton(AF_INET, cp, &in_addr->sin_addr); if (ret <= 0) goto err; } else if (strchr(cp, ':')) { in6_addr = (struct sockaddr_in6 *)¶ms.spp_address; in6_addr->sin6_port = htons(remote_port); in6_addr->sin6_family = AF_INET6; ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr); if (ret <= 0) goto err; } else goto err; } ret = setsockopt(sk, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, sizeof(struct sctp_paddrparams)); if (ret < 0) goto err; return; err: if (!errno) errno = EINVAL; fprintf(stderr, "%s: error %s peer_addr_params: %s.\n", argv0, (set)?"setting":"getting", strerror(errno)); } static int nodelay_func(char *argv0, int sk, int val, int set) { socklen_t optlen; int error; if (set) { error = setsockopt(sk, SOL_SCTP, SCTP_NODELAY, (char *)&val, sizeof(val)); } else { optlen = sizeof(val); error = getsockopt(sk, SOL_SCTP, SCTP_NODELAY, (char *)&val, &optlen); } if (error != 0) { fprintf(stderr, "%s: Error setting/getting nodelay: %s.\n", argv0, strerror(errno)); exit(1); } if (!set) { printf("nodelay is %d.\n", val); } return error; } static int maxseg_func(char *argv0, int sk, int val, int set) { socklen_t optlen; int error; if (set) { error = setsockopt(sk, SOL_SCTP, SCTP_MAXSEG, (char *)&val, sizeof(val)); } else { optlen = sizeof(val); error = getsockopt(sk, SOL_SCTP, SCTP_MAXSEG, (char *)&val, &optlen); } if (error != 0) { fprintf(stderr, "%s: Error setting/getting maxseg: %s.\n", argv0, strerror(errno)); exit(1); } if (!set) { printf("maxseg is %d.\n", val); } return error; } static int shutdown_func(char *argv0, int *skp, int shutdown_type) { struct msghdr outmessage; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; int error=0, bytes_sent; struct sctp_sndrcvinfo *sinfo; struct hostent *hst; char *sd_type; int sk = *skp; if (shutdown_type == SHUTDOWN_ABORT) sd_type = "ABORT"; else sd_type = "SHUTDOWN"; /* Verify that the association is present. */ error = test_sk_for_assoc(sk, associd); if (error != 0) { printf("The association isn't present yet! Cannot %s!\n", sd_type); return -1; } if (socket_type == SOCK_SEQPACKET) { /* Set up the destination. */ if (remote_host) { hst = gethostbyname(remote_host); if (hst == NULL) { hst = gethostbyname2(remote_host, AF_INET6); } if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, remote_host); exit(1); } ra_family = hst->h_addrtype; switch (ra_family) { case AF_INET: ra_len = sizeof(remote_addr.v4); ra_raw = &remote_addr.v4.sin_addr; remote_addr.v4.sin_port = htons(remote_port); remote_addr.v4.sin_family = AF_INET; break; case AF_INET6: ra_len = sizeof(remote_addr.v6); ra_raw = &remote_addr.v6.sin6_addr; remote_addr.v6.sin6_port = htons(remote_port); remote_addr.v6.sin6_family = AF_INET6; break; default: fprintf(stderr, "Invalid address type.\n"); exit(1); break; } memcpy(ra_raw, hst->h_addr_list[0], hst->h_length); } /* Initialize the message struct we use to pass messages to * the remote socket. */ outmessage.msg_name = &remote_addr; outmessage.msg_namelen = ra_len; outmessage.msg_iov = NULL; outmessage.msg_iovlen = 0; 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)); if (shutdown_type == SHUTDOWN_ABORT) sinfo->sinfo_flags |= SCTP_ABORT; else sinfo->sinfo_flags |= SCTP_EOF; sinfo->sinfo_assoc_id = associd; bytes_sent = sendmsg(sk, &outmessage, 0); if (bytes_sent != 0) { printf("Failure: %s.\n", strerror(errno)); return -1; } /* Receive the COMM_LOST or SHUTDOWN_COMP event. */ test_recv_assoc_change(sk); } else { if (shutdown_type == SHUTDOWN_ABORT) { struct linger { int l_onoff; int l_linger; } data = {1, 0}; error = setsockopt(sk, SOL_SOCKET, SO_LINGER, (char *)&data, sizeof(data)); if (error != 0) { printf("setsockopt failed %s\n", strerror(errno)); exit(1); } } error = close(sk); if (error != 0) { printf("close failed %s\n", strerror(errno)); exit(1); } *skp = sk = build_endpoint(argv0, local_port); } /* Verify that the association is no longer present. */ error = test_sk_for_assoc(sk, associd); if (error != 0) { printf("Successfully %s the original association\n", sd_type); associd = 0; new_connection = 1; } else { printf("%s failed\n", sd_type); exit(1); } return 0; } static int get_assocstats_func(int sk, sctp_assoc_t assoc_id) { int error = 0; struct sctp_assoc_stats stats; socklen_t len; if (assoc_id == 0) { printf("No association present yet\n"); return -1; } memset(&stats, 0, sizeof(struct sctp_assoc_stats)); stats.sas_assoc_id = assoc_id; len = sizeof(struct sctp_assoc_stats); error = getsockopt(sk, SOL_SCTP, SCTP_GET_ASSOC_STATS, (char *)&stats, &len); if (error != 0) { printf("get_assoc_stats() failed %s\n", strerror(errno)); return error; } printf("Retransmitted Chunks: %" PRIu64 "\n", (uint64_t) stats.sas_rtxchunks); printf("Gap Acknowledgements Received: %" PRIu64 "\n", (uint64_t) stats.sas_gapcnt); printf("TSN received > next expected: %" PRIu64 "\n", (uint64_t) stats.sas_outofseqtsns); printf("SACKs sent: %" PRIu64 "\n", (uint64_t) stats.sas_osacks); printf("SACKs received: %" PRIu64 "\n", (uint64_t) stats.sas_isacks); printf("Control chunks sent: %" PRIu64 "\n", (uint64_t) stats.sas_octrlchunks); printf("Control chunks received: %" PRIu64 "\n", (uint64_t) stats.sas_ictrlchunks); printf("Ordered data chunks sent: %" PRIu64 "\n", (uint64_t) stats.sas_oodchunks); printf("Ordered data chunks received: %" PRIu64 "\n", (uint64_t) stats.sas_iodchunks); printf("Unordered data chunks sent: %" PRIu64 "\n", (uint64_t) stats.sas_ouodchunks); printf("Unordered data chunks received: %" PRIu64 "\n", (uint64_t) stats.sas_iuodchunks); printf("Dups received (ordered+unordered): %" PRIu64 "\n", (uint64_t) stats.sas_idupchunks); printf("Packets sent: %" PRIu64 "\n", (uint64_t) stats.sas_opackets); printf("Packets received: %" PRIu64 "\n", (uint64_t) stats.sas_ipackets); printf("Maximum Observed RTO this period: %" PRIu64 " - Transport: ", (uint64_t) stats.sas_maxrto); print_sockaddr((struct sockaddr *)&stats.sas_obs_rto_ipaddr); printf("\n"); return 0; } static int test_sk_for_assoc(int sk, sctp_assoc_t assoc_id) { int error = 0; struct sctp_status status; socklen_t status_len; memset(&status, 0, sizeof(status)); if (assoc_id) status.sstat_assoc_id = assoc_id; status_len = sizeof(struct sctp_status); error = getsockopt(sk, SOL_SCTP, SCTP_STATUS, (char *)&status, &status_len); return error; } /* Receive a notification and return the corresponding associd if the event is * SCTP_COMM_UP. Return 0 for any other event. */ static sctp_assoc_t test_recv_assoc_change(int sk) { struct msghdr inmessage; struct iovec iov; char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; int error; /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) { printf("%s: Can't allocate memory.\n", __FUNCTION__); exit(1); } iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); error = recvmsg(sk, &inmessage, MSG_WAITALL); if (error < 0) { printf("%s: recvmsg: %s\n", __FUNCTION__, strerror(errno)); exit(1); } return test_verify_assoc_change(&inmessage); } /* Verify a notification and return the corresponding associd if the event is * SCTP_COMM_UP. Return 0 for any other event. */ static sctp_assoc_t test_verify_assoc_change(struct msghdr *msg) { union sctp_notification *sn; if (!(msg->msg_flags & MSG_NOTIFICATION)) { fprintf(stderr, "%s: Received data when notification is expected\n", __FUNCTION__); exit(1); } sn = (union sctp_notification *)msg->msg_iov->iov_base; if (SCTP_ASSOC_CHANGE != sn->sn_header.sn_type) { fprintf(stderr, "%s: Received unexpected notification: %d", __FUNCTION__, sn->sn_header.sn_type); exit(1); } switch(sn->sn_assoc_change.sac_state) { case SCTP_COMM_UP: printf("Recieved SCTP_COMM_UP\n"); break; case SCTP_COMM_LOST: printf("Recieved SCTP_COMM_LOST\n"); break; case SCTP_RESTART: printf("Recieved SCTP_RESTART\n"); break; case SCTP_SHUTDOWN_COMP: printf("Recieved SCTP_SHUTDOWN_COMP\n"); break; case SCTP_CANT_STR_ASSOC: printf("Recieved SCTP_CANT_STR_ASSOC\n"); break; } if (SCTP_COMM_UP == sn->sn_assoc_change.sac_state) return sn->sn_assoc_change.sac_assoc_id; else return 0; } void print_addr_buf(void * laddrs, int n_laddrs) { void *addr_buf = laddrs; int i; for (i = 0; i < n_laddrs; i++) { addr_buf += print_sockaddr((struct sockaddr *)addr_buf); printf("\n"); } } int print_sockaddr(struct sockaddr *sa_addr) { struct sockaddr_in *in_addr; struct sockaddr_in6 *in6_addr; if (AF_INET == sa_addr->sa_family) { in_addr = (struct sockaddr_in *)sa_addr; printf("%d.%d.%d.%d:%d", NIPQUAD(in_addr->sin_addr), ntohs(in_addr->sin_port)); return sizeof(struct sockaddr_in); } else { in6_addr = (struct sockaddr_in6 *)sa_addr; printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%d", NIP6(in6_addr->sin6_addr), ntohs(in6_addr->sin6_port)); return sizeof(struct sockaddr_in6); } } lksctp-tools-1.0.16+dfsg.orig/src/apps/myftp.c0000644000175000017500000002576012300634451020746 0ustar michaelmichael/* myftp - simple file transfer over sctp testing tool. * Copyright (c) 2002 Intel Corp. * * This file is part of the LKSCTP kernel Implementation. This * is a submission by Xingang Guo from the Intel Corporation while * participating on the LKSCTP project. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Written or modified by: * Xingang Guo * Jon Grimm * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #define BUFSIZE 1024 static char buffer[BUFSIZE]; #define DUMP_CORE { char *diediedie = 0; *diediedie = 0; } typedef enum { COMMAND_NONE, COMMAND_RECV, COMMAND_SEND } command_t; /* These are the global options. */ #define MAX_NUM_HOST 5 static char *local_host[MAX_NUM_HOST]; static int num_local_host = 0; static int local_port = 4444; static int buffer_size = BUFSIZE; static char *remote_host = NULL; static int remote_port = 4444; static command_t command = COMMAND_NONE; static char *filename = NULL; static int interactive = 0; static unsigned long delay = 0; static int verbose = 0; static void usage(char *argv0) { fprintf(stderr, "Usage: %s [options]\n",argv0); fprintf(stderr, "Options:\n"); fprintf(stderr, "\t--local, -H Specify local interface\n"); fprintf(stderr, "\t--local-port, -P Specify local port (default 4444)\n"); fprintf(stderr, "\t--remote, -h Specify interface on remote host\n"); fprintf(stderr, "\t--remote-port, -p Specify remote port (default 4444)\n"); fprintf(stderr, "\t--listen, -l Work in receiving mode\n"); fprintf(stderr, "\t--send, -s Work in sending mode\n"); fprintf(stderr, "\t--file, -f File to read or write,\n"); fprintf(stderr, "\t--buffer, -b Buffer size. (default 1024 bytes)\n"); fprintf(stderr, "\t by default use standard input/output.\n"); fprintf(stderr, "\t--quick, -q Send packets continueously,\n"); fprintf(stderr, "\t do not wait for key. Default wait.\n"); fprintf(stderr, "\t--delay, -d Delay between consecutive sends (see --quick)\n"); fprintf(stderr, "\t--verbose, -v In verbose mode, display the progress.\n"); fprintf(stderr, "\n\t--help, Print this message.\n\n"); } /* usage() */ static int parse_arguments(int argc, char *argv[]) { int option_index = 0; int c; static struct option long_options[] = { {"local", 1, 0, 1}, {"local-port", 1, 0, 2}, {"remote", 1, 0, 3}, {"remote-port", 1, 0, 4}, {"file", 1, 0, 5}, {"delay", 1, 0, 6}, {"buffer", 1, 0, 7}, {"listen", 0, 0, 10}, {"send", 0, 0, 11}, {"quick", 0, 0, 12}, {"verbose", 0, 0, 13}, {"help", 0, 0, 99}, {0, 0, 0, 0} }; /* Parse the arguments. */ while (1) { c = getopt_long(argc, argv, "H:P:h:p:f:d:b:qlsv",long_options,&option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case 1: /* local host */ case 'H': local_host[num_local_host++] = optarg; break; case 2: /* local port */ case 'P': local_port = atoi(optarg); break; case 3: /* remote host */ case 'h': remote_host = optarg; break; case 4: /* remote port */ case 'p': remote_port = atoi(optarg); break; case 5: case 'f': filename = optarg; break; case 6: case 'd': delay = strtoul(optarg,NULL,10); printf("delay is %ld usec\n",delay); break; case 7: case 'b': buffer_size = atoi(optarg); if ( buffer_size > BUFSIZE ) { buffer_size = BUFSIZE; fprintf(stderr,"Warning, buffer size too large, set to %d\n",buffer_size); } case 12: case 'q': interactive = 0; break; case 13: case 'v': verbose = 1; break; /* COMMANDS */ case 10: /* listen */ case 'l': if (command) { fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]); return 1; } else command = COMMAND_RECV; break; case 11: /* send */ case 's': if (command) { fprintf(stderr, "%s: pick ONE of listen or send\n", argv[0]); return 2; } else command = COMMAND_SEND; break; case '?': case 99: usage(argv[0]); return 3; break; default: printf ("%s: unrecognized option 0%c\n", argv[0], c); usage(argv[0]); return 4; } } if (optind < argc) { fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]); while (optind < argc) fprintf(stderr, "%s ", argv[optind++]); fprintf(stderr, "\n"); usage(argv[0]); return 5; } if (0 == num_local_host) { fprintf(stderr, "%s: You MUST provide a local host.\n", argv[0]); usage(argv[0]); return 6; } if ( filename == NULL && command == COMMAND_SEND) fprintf(stderr,"%s: Use standard input to send\n",argv[0]); if ( filename == NULL && command == COMMAND_RECV ) fprintf(stderr,"%s: Use standard output to write\n",argv[0]); return 0; } /* parse_arguments() */ static void emsg(char *prog,char *s) { if ( prog != NULL ) fprintf(stderr,"%s: ",prog); perror(s); fflush(stdout); //DUMP_CORE; exit(-1); } static int build_endpoint(char *argv0) { int retval,i; /* Create the local endpoint. */ if ( (retval = socket(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0 ) { emsg(argv0,"socket"); exit(retval); } for ( i = 0;i < num_local_host;i++ ) { struct hostent *hst; struct sockaddr_in laddr; /* Get the transport address for the local host name. */ fprintf(stderr,"Hostname %d is %s\n",i+1,local_host[i]); if ( (hst = gethostbyname(local_host[i])) == NULL ) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host[i]); exit(1); } memcpy(&laddr.sin_addr, hst->h_addr_list[0],sizeof(laddr.sin_addr)); laddr.sin_port = htons(local_port); laddr.sin_family = AF_INET; /* Bind this socket to the test port. */ if ( bind(retval, (struct sockaddr *)&laddr, sizeof(laddr)) ) { emsg(argv0,"bind"); exit(-1); } } fprintf(stderr,"Endpoint built.\n"); return retval; } /* build_endpoint() */ /* Convenience structure to determine space needed for cmsg. */ typedef union { struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcvinfo; } _sctp_cmsg_data_t; /* Listen on the socket, printing out anything that arrives. */ static void command_recv(char *argv0, int sk) { struct msghdr inmessage; char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))]; struct iovec iov; int ret; int fd; int ct; listen(sk, 1); /* Initialize inmessage with enough space for DATA... */ memset(&inmessage, 0, sizeof(inmessage)); iov.iov_base = buffer; iov.iov_len = buffer_size; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; /* or a control message. */ inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); /* creat a file */ if ( filename == NULL ) fd = 1; else if ( (fd = open(filename,O_WRONLY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE)) == -1 ) emsg(argv0,"open"); fprintf(stderr,"%s Receiving...\n", argv0); /* Get the messages sent */ ct = 0; while ( (ret = recvmsg(sk, &inmessage, MSG_WAITALL)) >= 0 ) { if ( verbose ) fprintf(stderr,"%s-%d received %d bytes\n", argv0, ++ct, ret); if ( !(inmessage.msg_flags & MSG_NOTIFICATION) ) { //printf("%s write %d bytes\n",argv0,ret); if ( write(fd,buffer,ret) != ret ) emsg(argv0,"write"); } else { union sctp_notification *sn; sn = (union sctp_notification *)iov.iov_base; if ((sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) && (sn->sn_assoc_change.sac_state == SCTP_SHUTDOWN_COMP)) break; } } if ( ret < 0 ) emsg(argv0,"recvmsg"); close(fd); close(sk); } /* command_recv() */ /* Read lines from stdin and send them to the socket. */ static void command_send(char *argv0, int sk) { struct msghdr outmsg; struct iovec iov; struct hostent *hst; struct sockaddr_in remote_addr; int fd; int msglen; int ct; /* Set up the destination. */ hst = gethostbyname(remote_host); if (hst == NULL || hst->h_length < 1) { fprintf(stderr, "%s: bad hostname: %s\n", argv0, remote_host); exit(1); } memcpy(&remote_addr.sin_addr, hst->h_addr_list[0], sizeof(remote_addr.sin_addr)); remote_addr.sin_port = htons(remote_port); remote_addr.sin_family = AF_INET; /* Initialize the message struct we use to pass messages to * the remote socket. */ iov.iov_base = buffer; iov.iov_len = buffer_size; outmsg.msg_iov = &iov; outmsg.msg_iovlen = 1; outmsg.msg_control = NULL; outmsg.msg_controllen = 0; outmsg.msg_name = &remote_addr; outmsg.msg_namelen = sizeof(remote_addr); /* open the file */ if ( filename == NULL ) fd = 0; else if ( (fd = open(filename,O_RDONLY)) == -1 ) emsg(argv0,"open"); fprintf(stderr,"%s ready to send...\n", argv0); ct = 0; while ( (msglen = read(fd,buffer,buffer_size)) > 0 ) { /* Send to our neighbor. */ iov.iov_len = msglen; if ( sendmsg(sk, &outmsg, 0) != msglen ) emsg(argv0,"sendmsg"); if ( verbose ) fprintf(stderr,"%s-%d send %d bytes\n",argv0,++ct,msglen); if ( interactive && fd != 1 ) getchar(); // no flow control? no problem, make it slow else if ( delay > 0 ) usleep(delay); } while ( msglen > 0 ); close(fd); close(sk); } /* command_send() */ int main(int argc, char *argv[]) { int ret; if (( ret = parse_arguments(argc, argv) )) return ret; switch(command) { case COMMAND_NONE: fprintf(stderr, "%s: Please specify a command.\n", argv[0]); break; case COMMAND_RECV: command_recv(argv[0],build_endpoint(argv[0])); break; case COMMAND_SEND: command_send(argv[0],build_endpoint(argv[0])); break; default: fprintf(stderr, "%s: illegal command %d\n", argv[0], command); } /* switch(command) */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/apps/peel_client.c0000644000175000017500000004611112300634451022063 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2003 * * 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. * * In addition: * * Copyright (c) 2003 Cisco * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * c) Neither the name of Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers * * 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: * Randall Stewart * Sridhar Samudrala */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __NetBSD__ #include #endif #define SCTP_CRC32C_POLY 0x1EDC6F41 #define SCTP_CRC32C(c,d) (c=(c>>8)^sctp_crc_c[(c^(d))&0xFF]) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* Copyright 2001, D. Otis. Use this program, code or tables */ /* extracted from it, as desired without restriction. */ /* */ /* 32 Bit Reflected CRC table generation for SCTP. */ /* To accommodate serial byte data being shifted out least */ /* significant bit first, the table's 32 bit words are reflected */ /* which flips both byte and bit MS and LS positions. The CRC */ /* is calculated MS bits first from the perspective of the serial*/ /* stream. The x^32 term is implied and the x^0 term may also */ /* be shown as +1. The polynomial code used is 0x1EDC6F41. */ /* Castagnoli93 */ /* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+ */ /* x^11+x^10+x^9+x^8+x^6+x^0 */ /* Guy Castagnoli Stefan Braeuer and Martin Herrman */ /* "Optimization of Cyclic Redundancy-Check Codes */ /* with 24 and 32 Parity Bits", */ /* IEEE Transactions on Communications, Vol.41, No.6, June 1993 */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static unsigned char buffer1[4100]; static unsigned char buffer2[4100]; static unsigned char buffer3[4100]; static unsigned char buffer4[4100]; static struct sockaddr_in bindto,got,to; static socklen_t len; unsigned long sctp_crc_c[256] = { 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L, }; u_int32_t update_crc32(u_int32_t crc32, unsigned char *buffer, unsigned int length) { int i; for (i = 0; i < length; i++) { SCTP_CRC32C(crc32, buffer[i]); } return (crc32); } u_int32_t sctp_csum_finalize(u_int32_t crc32) { u_int32_t result; #if BYTE_ORDER == BIG_ENDIAN u_int8_t byte0, byte1, byte2, byte3; #endif /* Complement the result */ result = ~crc32; #if BYTE_ORDER == BIG_ENDIAN /* * For BIG-ENDIAN.. aka Motorola byte order the result is in * little-endian form. So we must manually swap the bytes. Then * we can call htonl() which does nothing... */ byte0 = result & 0x000000ff; byte1 = (result >> 8) & 0x000000ff; byte2 = (result >> 16) & 0x000000ff; byte3 = (result >> 24) & 0x000000ff; result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); crc32 = htonl(result); #else /* * For INTEL platforms the result comes out in network order. * No htonl is required or the swap above. So we optimize out * both the htonl and the manual swap above. */ crc32 = result; #endif return (crc32); } static u_int32_t at = 468700; void prepare_buffers(void) { /* Prepare buffers */ u_int32_t temp,*p; int i; p = (u_int32_t *)buffer1; for(i=0;i<(sizeof(buffer1)/4);i++){ *p = at; at++; p++; } /* backup over the last int */ p--; *p = 0; temp = 0xffffffff; temp = update_crc32(temp,buffer1,(sizeof(buffer1)-4)); *p = sctp_csum_finalize(temp); p = (u_int32_t *)buffer2; for(i=0;i<(sizeof(buffer2)/4);i++){ *p = at; at++; p++; } p--; *p = 0; temp = 0xffffffff; temp = update_crc32(temp,buffer2,(sizeof(buffer2)-4)); *p = sctp_csum_finalize(temp); p = (u_int32_t *)buffer3; for(i=0;i<(sizeof(buffer3)/4);i++){ *p = at; at++; p++; } p--; *p = 0; temp = 0xffffffff; temp = update_crc32(temp,buffer3,(sizeof(buffer3)-4)); *p = sctp_csum_finalize(temp); p = (u_int32_t *)buffer4; for(i=0;i<(sizeof(buffer4)/4);i++){ *p = at; at++; p++; } p--; *p = 0; temp = 0xffffffff; temp = update_crc32(temp,buffer4,(sizeof(buffer4)-4)); *p = sctp_csum_finalize(temp); } static int my_handle_notification(int fd,char *notify_buf) { union sctp_notification *snp; struct sctp_assoc_change *sac; struct sctp_paddr_change *spc; struct sctp_remote_error *sre; struct sctp_send_failed *ssf; struct sctp_shutdown_event *sse; int asocDown; char *str; char buf[256]; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; asocDown = 0; snp = (union sctp_notification *)notify_buf; switch(snp->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: sac = &snp->sn_assoc_change; switch(sac->sac_state) { case SCTP_COMM_UP: str = "COMMUNICATION UP"; break; case SCTP_COMM_LOST: str = "COMMUNICATION LOST"; asocDown = 1; break; case SCTP_RESTART: str = "RESTART"; break; case SCTP_SHUTDOWN_COMP: str = "SHUTDOWN COMPLETE"; asocDown = 1; break; case SCTP_CANT_STR_ASSOC: str = "CANT START ASSOC"; printf("EXIT:SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str, (uint32_t)sac->sac_assoc_id); exit(0); break; default: str = "UNKNOWN"; } /* end switch(sac->sac_state) */ printf("SCTP_ASSOC_CHANGE: %s, assoc=%xh\n", str, (uint32_t)sac->sac_assoc_id); break; case SCTP_PEER_ADDR_CHANGE: spc = &snp->sn_paddr_change; switch(spc->spc_state) { case SCTP_ADDR_AVAILABLE: str = "ADDRESS AVAILABLE"; break; case SCTP_ADDR_UNREACHABLE: str = "ADDRESS UNAVAILABLE"; break; case SCTP_ADDR_REMOVED: str = "ADDRESS REMOVED"; break; case SCTP_ADDR_ADDED: str = "ADDRESS ADDED"; break; case SCTP_ADDR_MADE_PRIM: str = "ADDRESS MADE PRIMARY"; break; default: str = "UNKNOWN"; } /* end switch */ sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; if (sin6->sin6_family == AF_INET6) { inet_ntop(AF_INET6, (char*)&sin6->sin6_addr, buf, sizeof(buf)); } else { sin = (struct sockaddr_in *)&spc->spc_aaddr; inet_ntop(AF_INET, (char*)&sin->sin_addr, buf, sizeof(buf)); } printf("SCTP_PEER_ADDR_CHANGE: %s, addr=%s, assoc=%xh\n", str, buf, (uint32_t)spc->spc_assoc_id); break; case SCTP_REMOTE_ERROR: sre = &snp->sn_remote_error; printf("SCTP_REMOTE_ERROR: assoc=%xh\n", (uint32_t)sre->sre_assoc_id); break; case SCTP_SEND_FAILED: ssf = &snp->sn_send_failed; printf("SCTP_SEND_FAILED: assoc=%xh\n", (uint32_t)ssf->ssf_assoc_id); break; case SCTP_ADAPTATION_INDICATION: { struct sctp_adaptation_event *ae; ae = &snp->sn_adaptation_event; printf("\nSCTP_adaptation_indication bits:0x%x\n", (u_int)ae->sai_adaptation_ind); } break; case SCTP_PARTIAL_DELIVERY_EVENT: { struct sctp_pdapi_event *pdapi; pdapi = &snp->sn_pdapi_event; printf("SCTP_PD-API event:%u\n", pdapi->pdapi_indication); if(pdapi->pdapi_indication == 0){ printf("PDI- Aborted\n"); } } break; case SCTP_SHUTDOWN_EVENT: sse = &snp->sn_shutdown_event; printf("SCTP_SHUTDOWN_EVENT: assoc=%xh\n", (uint32_t)sse->sse_assoc_id); break; default: printf("Unknown notification event type=%xh\n", snp->sn_header.sn_type); } /* end switch(snp->sn_type) */ if(asocDown){ printf("Bring association back up\n"); len = sizeof(to); if(connect(fd,(struct sockaddr *)&to,len) == -1){ printf("Sorry connect fails %d\n",errno); } return(1); } return(0); } int my_sctpReadInput(int fd) { /* receive some number of datagrams and * act on them. */ int sz; struct msghdr msg; struct iovec iov[2]; unsigned char from[200]; char readBuffer[65535]; char controlVector[65535]; iov[0].iov_base = readBuffer; iov[0].iov_len = sizeof(readBuffer); iov[1].iov_base = NULL; iov[1].iov_len = 0; msg.msg_name = (caddr_t)from; msg.msg_namelen = sizeof(from); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = (caddr_t)controlVector; msg.msg_controllen = sizeof(controlVector); errno = 0; sz = recvmsg(fd,&msg,0); if(sz <= 0){ printf("Read returns %d errno:%d control len is %zu msgflg:%x\n", sz,errno, msg.msg_controllen,msg.msg_flags); } if (msg.msg_flags & MSG_NOTIFICATION) { return(my_handle_notification(fd,readBuffer)); }else{ printf("Huh, I got data?.. ignored (%d bytes)\n",sz); return(0); } } int clear_fds(int fd,int fd1) { int felldown; int max,notdone; fd_set readfds,writefds,exceptfds; struct timeval tv; memset(&tv,0,sizeof(tv)); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); felldown = 0; FD_SET(fd,&readfds); FD_SET(fd1,&readfds); if(fd > fd1){ max = fd + 1; }else{ max = fd1 + 1; } notdone = 1; while(notdone){ select(max,&readfds,&writefds,&exceptfds,&tv); notdone = 0; if(FD_ISSET(fd,&readfds)){ notdone++; printf("clearing fd:%d\n",fd); felldown += my_sctpReadInput(fd); notdone = 1; } if(FD_ISSET(fd1,&readfds)){ notdone++; printf("clearing fd1:%d\n",fd1); felldown += my_sctpReadInput(fd1); } } return(felldown); } void process_out_data(int fd,int fd1) { int notdone,x,ret; while(1){ /* Prepare the buffers */ prepare_buffers(); /* send out the 4 buffers */ ret = sendto(fd,buffer1,sizeof(buffer1),0, (struct sockaddr *)&to,sizeof(to)); if(ret < sizeof(buffer1)){ printf("Gak1, error:%d ret:%d\n",errno,ret); } ret = sendto(fd1,buffer2,sizeof(buffer1),0, (struct sockaddr *)&to,sizeof(to)); if(ret < sizeof(buffer2)){ printf("Gak2, error:%d ret:%d\n",errno,ret); } ret = sendto(fd,buffer3,sizeof(buffer1),0, (struct sockaddr *)&to,sizeof(to)); if(ret < sizeof(buffer3)){ printf("Gak3, error:%d ret:%d\n",errno,ret); } ret = sendto(fd1,buffer4,sizeof(buffer1),0, (struct sockaddr *)&to,sizeof(to)); if(ret < sizeof(buffer4)){ printf("Gak4, error:%d ret:%d\n",errno,ret); } /* now wait until we get a assoc failing */ notdone = 1; while(notdone){ x = clear_fds(fd,fd1); if(x){ notdone = 0; } sleep(1); } } } int main(int argc, char **argv) { int i,fd,fd1; char *addr=NULL; uint16_t port=0; int protocol_touse = IPPROTO_SCTP; struct sctp_event_subscribe event; while((i= getopt(argc,argv,"p:h:")) != EOF){ switch(i){ case 'h': addr = optarg; break; case 'p': port = (uint16_t)strtol(optarg,NULL,0); break; }; } memset(&to,0,sizeof(to)); if((addr == NULL) || (port == 0)){ printf("Usage: %s -h addr -p port\n", argv[0]); return(-1); } if(inet_pton(AF_INET, addr, (void *) &to.sin_addr)){ //to.sin_len = sizeof(to); to.sin_family = AF_INET; printf("port selected is %d\n",port); printf("addr %x\n",(u_int)ntohl(to.sin_addr.s_addr)); to.sin_port = htons(port); }else{ printf("Can't translate the address\n"); return(-1); } /**********************socket 1 *******************/ fd = socket(AF_INET, SOCK_SEQPACKET, protocol_touse); if(fd == -1){ printf("can't open socket:%d\n",errno); return(-1); } memset(&bindto,0,sizeof(bindto)); //len = bindto.sin_len = sizeof(bindto); len = sizeof(bindto); bindto.sin_family = AF_INET; bindto.sin_port = 0; if(bind(fd,(struct sockaddr *)&bindto, len) < 0){ printf("can't bind a socket:%d\n",errno); close(fd); return(-1); } if(getsockname(fd,(struct sockaddr *)&got,&len) < 0){ printf("get sockname failed err:%d\n",errno); close(fd); return(-1); } printf("fd uses port %d\n",ntohs(got.sin_port)); /**********************socket 2 *******************/ fd1 = socket(AF_INET, SOCK_SEQPACKET, protocol_touse); if(fd1 == -1){ printf("can't open socket:%d\n",errno); close(fd); return(-1); } memset(&bindto,0,sizeof(bindto)); //len = bindto.sin_len = sizeof(bindto); len = sizeof(bindto); bindto.sin_family = AF_INET; bindto.sin_port = 0; if(bind(fd1,(struct sockaddr *)&bindto, len) < 0){ printf("can't bind a socket:%d\n",errno); close(fd); close(fd1); return(-1); } if(getsockname(fd1,(struct sockaddr *)&got,&len) < 0){ printf("get sockname failed err:%d\n",errno); close(fd); close(fd1); return(-1); } printf("fd1 uses port %d\n",ntohs(got.sin_port)); /* enable all event notifications */ event.sctp_data_io_event = 1; event.sctp_association_event = 1; event.sctp_address_event = 1; event.sctp_send_failure_event = 1; event.sctp_peer_error_event = 1; event.sctp_shutdown_event = 1; event.sctp_partial_delivery_event = 1; event.sctp_adaptation_layer_event = 1; if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) { printf("Gak, can't set events errno:%d\n",errno); exit(0); } if (setsockopt(fd1, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) { printf("Gak, can't set events errno:%d\n",errno); exit(0); } if(connect(fd,(struct sockaddr *)&to,len) == -1){ printf("Sorry connect fails %d\n",errno); close(fd); return(-1); } if(connect(fd1,(struct sockaddr *)&to,len) == -1){ printf("Sorry connect fails %d\n",errno); close(fd); return(-1); } printf("Connected\n"); clear_fds(fd,fd1); process_out_data(fd,fd1); return(0); } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/0000755000175000017500000000000012300634451020643 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_sendto.c0000644000175000017500000001223712300634451024511 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the sendto () call * for 1-1 style sockets * * TEST1: Sending data from client socket to server socket * TEST2: Sending data from accept (server) socket to client socket * TEST3: Sending data from unconnected client socket to server * TEST4: sending partial data from a buffer * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 4; int TST_CNT = 0; int main(int argc, char *argv[]) { int msg_count; socklen_t len; int sk,sk1,pf_class,lstn_sk,acpt_sk,flag; char *message = "hello, world!\n"; char *message_rcv; int count; struct sockaddr_in conn_addr,lstn_addr,svr_addr; /* Rather than fflush() throughout the code, set stdout to * be unbufferd */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); message_rcv = malloc(512); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); flag = MSG_NOSIGNAL; test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); msg_count = strlen(message) + 1; /*sendto() TEST1: Sending data from client socket to server socket*/ count = sendto(sk, message, msg_count, flag, (const struct sockaddr *) &conn_addr, len); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendto from client to server " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendto() from client to server - SUCCESS"); test_recv(acpt_sk, message_rcv, msg_count, flag); strncpy(message_rcv,"\0",512); /*sendto() TEST2: Sending data from accept socket to client socket*/ count = sendto(acpt_sk, message, msg_count, flag, (const struct sockaddr *) &svr_addr, len); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendto from accept socket to client " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendto() from accept socket to client - SUCCESS"); test_recv(sk, message_rcv, msg_count, flag); close(sk); close(acpt_sk); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*sendto() TEST3: Sending data from unconnected client socket to server socket*/ count = sendto(sk1, message, msg_count, flag, (const struct sockaddr *) &conn_addr, len); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendto from unconnected client to " "server count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendto() from unconnected client to server - SUCCESS"); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); test_recv(acpt_sk, message_rcv, msg_count, flag); /*send() TEST4: Sending less number of data from the buffer*/ /*Sending only 5 bytes so that only hello is received*/ test_sendto(sk, message, 5 , flag, (const struct sockaddr *)&conn_addr, len); test_recv(acpt_sk, message_rcv, 5, flag); tst_resm(TPASS, "sendto() partial data from a buffer - SUCCESS"); close(sk1); close(lstn_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_connect.c0000644000175000017500000001626512300634451023511 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2002, 2003 * Copyright (c) 1999-2001 Motorola, 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * * Written or modified by: * Sridhar Samudrala */ /* This is a kernel test to verify the one-to-many style connect() in blocking * and non-blocking modes. */ #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 5; int TST_CNT = 0; int main(int argc, char *argv[]) { int svr_sk, clt_sk1, clt_sk2, peeloff_sk; sctp_assoc_t svr_associd1; sockaddr_storage_t svr_loop, clt_loop1, clt_loop2, clt_loop3; struct sctp_assoc_change *sac; struct iovec iov; struct msghdr inmessage; int error; char *big_buffer; int flags; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Initialize the server and client addresses. */ svr_loop.v4.sin_family = AF_INET; svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); clt_loop1.v4.sin_family = AF_INET; clt_loop1.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop1.v4.sin_port = htons(SCTP_TESTPORT_2); clt_loop2.v4.sin_family = AF_INET; clt_loop2.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop2.v4.sin_port = htons(SCTP_TESTPORT_2+1); clt_loop3.v4.sin_family = AF_INET; clt_loop3.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop3.v4.sin_port = htons(SCTP_TESTPORT_2+2); /* Create and bind the server socket. */ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop)); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 1); /* Create and bind the client sockets. */ clt_sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(clt_sk1, &clt_loop1.sa, sizeof(clt_loop1)); clt_sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(clt_sk2, &clt_loop2.sa, sizeof(clt_loop2)); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(svr_sk); test_enable_assoc_change(clt_sk1); test_enable_assoc_change(clt_sk2); /* Set clt_sk1 as non-blocking. */ flags = fcntl(clt_sk1, F_GETFL, 0); if (flags < 0) tst_brkm(TBROK, tst_exit, "fcntl F_GETFL: %s", strerror(errno)); if (fcntl(clt_sk1, F_SETFL, flags | O_NONBLOCK) < 0) tst_brkm(TBROK, tst_exit, "fcntl F_SETFL: %s", strerror(errno)); /* Do a non-blocking connect from clt_sk1 to svr_sk */ error = connect(clt_sk1, &svr_loop.sa, sizeof(svr_loop)); /* Non-blocking connect should return immediately with EINPROGRESS. */ if ((error != -1) || (EINPROGRESS != errno)) tst_brkm(TBROK, tst_exit, "non-blocking connect error: %d" "errno:%d", error, errno); tst_resm(TPASS, "non-blocking connect"); /* Doing a connect on a socket to create an association that is * is already established should return EISCONN. */ error = connect(clt_sk1, &svr_loop.sa, sizeof(svr_loop)); if ((error != -1) || (EISCONN != errno)) tst_brkm(TBROK, tst_exit, "connect on a socket to create an " "assoc that is already established error:%d errno:%d", error, errno); tst_resm(TPASS, "connect on a socket to create an assoc that is " "already established"); /* Initialize inmessage for all receives. */ memset(&inmessage, 0, sizeof(inmessage)); big_buffer = test_malloc(REALLY_BIG); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = NULL; /* Get COMM_UP on clt_sk1 */ error = test_recvmsg(clt_sk1, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; clt_associd1 = sac->sac_assoc_id; #endif /* Get COMM_UP on svr_sk */ error = test_recvmsg(svr_sk, &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; svr_associd1 = sac->sac_assoc_id; /* Do a blocking connect from clt_sk2 to svr_sk. * Blocking connect should block until the association is established * and return success. */ test_connect(clt_sk2, &svr_loop.sa, sizeof(svr_loop)); /* Get COMM_UP on clt_sk2 */ error = test_recvmsg(clt_sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; clt_associd2 = sac->sac_assoc_id; #endif /* Get COMM_UP on svr_sk */ error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; svr_associd2 = sac->sac_assoc_id; #endif tst_resm(TPASS, "blocking connect"); peeloff_sk = test_sctp_peeloff(svr_sk, svr_associd1); /* Doing a connect on a peeled off socket should fail. */ error = connect(peeloff_sk, &clt_loop3.sa, sizeof(clt_loop3)); if ((error != -1) || (EISCONN != errno)) tst_brkm(TBROK, tst_exit, "connect on a peeled off socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect on a peeled off socket"); /* Trying to create an association on a socket that matches an * existing peeled-off association should fail. */ error = connect(svr_sk, &clt_loop1.sa, sizeof(clt_loop1)); if ((error != -1) || (EADDRNOTAVAIL != errno)) tst_brkm(TBROK, tst_exit, "connect to create an assoc that " "matches a peeled off assoc error:%d errno:%d", error, errno); tst_resm(TPASS, "connect to create an assoc that matches a peeled off " "assoc"); close(svr_sk); close(clt_sk1); close(clt_sk2); close(peeloff_sk); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_accept_close.c0000644000175000017500000001771212300634451025644 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the accept () and close () call for * 1-1 style sockets * * accept () Tests: * --------------- * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: Invalid address * TEST4: On a non-listening socket * TEST5: On a established socket * TEST6: On a CLOSED association * TEST7: Extracting the association on the listening socket * * close () Tests: * -------------- * TEST8: Bad socket descriptor * TEST9: valid socket descriptor * TEST10: Closed socket descriptor * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 10; int TST_CNT = 0; #define SK_MAX 10 int main(int argc, char *argv[]) { socklen_t len; int i; int sk,lstn_sk,clnt_sk[SK_MAX],acpt_sk,pf_class; int new_sk[SK_MAX],clnt2_sk[SK_MAX]; int error; int fd, err_no = 0; char filename[21]; struct sockaddr_in conn_addr,lstn_addr,acpt_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); for (i=0 ; i < SK_MAX ; i++) new_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /* Creating a regular socket */ for (i = 0 ; i < SK_MAX ; i++) clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); for (i = 0 ; i < SK_MAX ; i++) clnt2_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /* Creating a listen socket */ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /* Binding the listen socket */ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /* Listening many sockets as we are calling too many connect here */ test_listen(lstn_sk, SK_MAX ); /* connect() is called just to make sure accept() doesn't block the * program */ i = 0; len = sizeof(struct sockaddr_in); test_connect(clnt_sk[i++], (struct sockaddr *) &conn_addr, len); /* accept() TEST1: Bad socket descriptor EBADF, Expected error */ error = accept(-1, (struct sockaddr *) &acpt_addr, &len); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "accept with a bad socket descriptor" "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept() with a bad socket descriptor - EBADF"); /*accept() TEST2: Invalid socket ENOTSOCK, Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = accept(fd, (struct sockaddr *) &acpt_addr, &len); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "accept with invalid socket" "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "accept() with invalid socket - ENOTSOCK"); /*accept() TEST3: Invalid address EFAULT, Expected error*/ error = accept(lstn_sk, (struct sockaddr *) -1, &len); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "accept with invalid address" "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept() with invalid address - EFAULT"); test_connect(clnt_sk[i++], (struct sockaddr *) &conn_addr, len); /*accept() TEST4: on a non-listening socket EINVAL, Expected error*/ error = accept(sk, (struct sockaddr *) &acpt_addr, &len); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "accept on a non-listening socket" "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept() on a non-listening socket - EINVAL"); test_connect(clnt_sk[i++], (struct sockaddr *) &conn_addr, len); /*Calling accept to establish the connection*/ acpt_sk = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len); /*accept() TEST5: On a established socket EINVAL, Expected error*/ error = accept(acpt_sk, (struct sockaddr *) &acpt_addr, &len); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "accept on an established socket" "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept() on an established socket - EINVAL"); /*Closing the previously established association*/ close(acpt_sk); test_connect(clnt_sk[i], (struct sockaddr *) &conn_addr, len); /*accept() TEST6: On the CLOSED association should succeed*/ acpt_sk = accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len); if (acpt_sk < 0) tst_brkm(TBROK, tst_exit, "accept a closed association" "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept() a closed association - SUCCESS"); close(acpt_sk); /*accept() TEST7: Extracting the association on the listening socket as new socket, new socket socket descriptor should return*/ for (i = 0 ; i < (SK_MAX - 1); i++) test_connect(clnt2_sk[i], (struct sockaddr *) &conn_addr, len); for (i = 0 ; i < (SK_MAX - 1); i++) new_sk[i] = test_accept(lstn_sk, (struct sockaddr *)&acpt_addr, &len); tst_resm(TPASS, "accept() on a listening socket - SUCCESS"); /*close() TEST8: Bad socket descriptor, EBADF Expected error*/ error = close(-1); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "close with a bad socket descriptor " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "close() with a bad socket descriptor - EBADF"); /*close() TEST9: valid socket descriptor should succeed*/ error = close(sk); if (error < 0) tst_brkm(TBROK, tst_exit, "close with a valid socket descriptor" " error:%d, errno:%d", error, errno); tst_resm(TPASS, "close() with a valid socket descriptor - SUCCESS"); /*close() TEST10: closed socket descriptor, EBADF Expected error*/ error = close(sk); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "close with a closed socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "close() with a closed socket descriptor - EBADF"); for (i = 0 ; i < SK_MAX ; i++) { close(clnt_sk[i]); close(new_sk[i]); close(clnt2_sk[i]); } return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_basic.c0000644000175000017500000003352512300634451023137 0ustar michaelmichael/* 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 * * 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: * La Monte H.P. Yarroll * Karl Knutson * Hui Huang * Jon Grimm * Sridhar Samudrala */ /* This is a basic functional test for the SCTP kernel * implementation state machine. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 15; int TST_CNT = 0; int main(void) { int sk1, sk2; sockaddr_storage_t loop1; sockaddr_storage_t loop2; sockaddr_storage_t msgname; 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; char *message = "hello, world!\n"; char *telephone = "Watson, come here! I need you!\n"; char *telephone_resp = "I already brought your coffee...\n"; int error, bytes_sent; int pf_class; uint32_t ppid; uint32_t stream; sctp_assoc_t associd1, associd2; struct sctp_assoc_change *sac; char *big_buffer; struct sockaddr *laddrs, *paddrs; int n_laddrs, n_paddrs, i; struct sockaddr *sa_addr; struct sockaddr_in *in_addr; struct sockaddr_in6 *in6_addr; void *addr_buf; /* 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; loop1.v6.sin6_family = AF_INET6; loop1.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_ANY_INIT; 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; loop1.v4.sin_family = AF_INET; loop1.v4.sin_addr.s_addr = INADDR_ANY; 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); tst_resm(TPASS, "socket"); /* Bind these sockets to the test ports. */ test_bind(sk1, &loop1.sa, sizeof(loop1)); test_bind(sk2, &loop2.sa, sizeof(loop2)); tst_resm(TPASS, "bind"); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(sk1); test_enable_assoc_change(sk2); /* 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; inmessage.msg_name = &msgname; /* Try to read on socket 2. This should fail since we are * neither listening, nor established. */ inmessage.msg_controllen = sizeof(incmsg); error = recvmsg(sk2, &inmessage, MSG_WAITALL); if (error > 0) tst_brkm(TBROK, tst_exit, "recvmsg on a socket neither" "listening nor established error: %d", error); tst_resm(TPASS, "recvmsg on a socket neither listening nor " "established"); /* Mark sk2 as being able to accept new associations. */ error = test_listen(sk2, 1); tst_resm(TPASS, "listen"); /* 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); tst_resm(TPASS, "sendmsg with a valid msg_name"); /* Get the communication up message on sk2. */ inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_namelen = sizeof(msgname); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); #if TEST_V6 if (inmessage.msg_namelen != sizeof(struct sockaddr_in6)) { DUMP_CORE; } if (msgname.v6.sin6_port != htons(SCTP_TESTPORT_1)) { DUMP_CORE; } if (msgname.v6.sin6_family != AF_INET6) { DUMP_CORE; } if (memcmp(&msgname.v6.sin6_addr, &in6addr_loopback, sizeof(msgname.v6.sin6_addr))) { DUMP_CORE; } #else if (inmessage.msg_namelen != sizeof(struct sockaddr_in)) { DUMP_CORE; } if (msgname.v4.sin_port != htons(SCTP_TESTPORT_1)) { DUMP_CORE; } if (msgname.v4.sin_family != AF_INET) { DUMP_CORE; } if (msgname.v4.sin_addr.s_addr != SCTP_IP_LOOPBACK) { DUMP_CORE; } #endif sac = (struct sctp_assoc_change *)iov.iov_base; associd2 = sac->sac_assoc_id; /* Get the communication up message on sk1. */ iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_control = incmsg; 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; tst_resm(TPASS, "recvmsg COMM_UP notifications"); /* Get the first message which was sent. */ inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_namelen = sizeof(msgname); memset(&msgname, 0, sizeof(msgname)); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); #if TEST_V6 if (inmessage.msg_namelen != sizeof(struct sockaddr_in6)) { DUMP_CORE; } if (msgname.v6.sin6_port != htons(SCTP_TESTPORT_1)) { DUMP_CORE; } if (msgname.v6.sin6_family != AF_INET6) { DUMP_CORE; } if (memcmp(&msgname.v6.sin6_addr, &in6addr_loopback, sizeof(msgname.v6.sin6_addr))) { DUMP_CORE; } #else if (inmessage.msg_namelen != sizeof(struct sockaddr_in)) { DUMP_CORE; } if (msgname.v4.sin_port != htons(SCTP_TESTPORT_1)) { DUMP_CORE; } if (msgname.v4.sin_family != AF_INET) { DUMP_CORE; } if (msgname.v4.sin_addr.s_addr != SCTP_IP_LOOPBACK) { DUMP_CORE; } #endif /* Try to send a message with NULL msg_name and associd, should fail */ 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; outmessage.msg_iov->iov_base = telephone; outmessage.msg_iov->iov_len = strlen(telephone) + 1; outmessage.msg_name = NULL; outmessage.msg_namelen = 0; bytes_sent = sendmsg(sk1, &outmessage, MSG_NOSIGNAL); if ((bytes_sent > 0) || (EPIPE != errno)) tst_brkm(TBROK, tst_exit, "sendmsg with NULL associd and " "NULL msg_name error:%d errno:%d", error, errno); tst_resm(TPASS, "sendmsg with NULL associd and NULL msg_name"); /* Fill in a incorrect assoc_id, which should cause an error. */ sinfo->sinfo_assoc_id = associd2; bytes_sent = sendmsg(sk1, &outmessage, MSG_NOSIGNAL); if ((bytes_sent > 0) || (EPIPE != errno)) tst_brkm(TBROK, tst_exit, "sendmsg with incorrect associd " "error:%d errno:%d", error, errno); tst_resm(TPASS, "sendmsg with incorrect associd"); /* Fill in a correct assoc_id and get back to the normal testing. */ sinfo->sinfo_assoc_id = associd1; /* Send two more messages, to cause a second SACK. */ test_sendmsg(sk1, &outmessage, 0, strlen(telephone)+1); outmessage.msg_name = &loop2; outmessage.msg_namelen = sizeof(loop2); outmessage.msg_iov->iov_base = telephone_resp; outmessage.msg_iov->iov_len = strlen(telephone_resp) + 1; test_sendmsg(sk1, &outmessage, 0, strlen(telephone_resp)+1); tst_resm(TPASS, "sendmsg with valid associd"); /* Get those two messages. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(telephone) + 1, MSG_EOR, stream, ppid); inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(telephone_resp) + 1, MSG_EOR, stream, ppid); tst_resm(TPASS, "recvmsg"); n_laddrs = sctp_getladdrs(sk1, associd1, &laddrs); if (n_laddrs <= 0) tst_brkm(TBROK, tst_exit, "sctp_getladdrs: %s", strerror(errno)); tst_resm(TPASS, "sctp_getladdrs"); addr_buf = (void *)laddrs; for (i = 0; i < n_laddrs; i++) { sa_addr = (struct sockaddr *)addr_buf; if (AF_INET == sa_addr->sa_family) { in_addr = (struct sockaddr_in *)sa_addr; tst_resm(TINFO, "LOCAL ADDR %d.%d.%d.%d PORT %d", NIPQUAD(in_addr->sin_addr), ntohs(in_addr->sin_port)); addr_buf += sizeof(struct sockaddr_in); } else { in6_addr = (struct sockaddr_in6 *)sa_addr; tst_resm(TINFO, "LOCAL ADDR %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x PORT %d", NIP6(in6_addr->sin6_addr), ntohs(in6_addr->sin6_port)); addr_buf += sizeof(struct sockaddr_in6); } } sctp_freeladdrs(laddrs); tst_resm(TPASS, "sctp_freeladdrs"); n_paddrs = sctp_getpaddrs(sk1, associd1, &paddrs); if (n_paddrs <= 0) tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno)); tst_resm(TPASS, "sctp_getpaddrs"); addr_buf = (void *)paddrs; for (i = 0; i < n_paddrs; i++) { sa_addr = (struct sockaddr *)addr_buf; if (AF_INET == sa_addr->sa_family) { in_addr = (struct sockaddr_in *)sa_addr; tst_resm(TINFO, "PEER ADDR %d.%d.%d.%d PORT %d", NIPQUAD(in_addr->sin_addr), ntohs(in_addr->sin_port)); addr_buf += sizeof(struct sockaddr_in); } else { in6_addr = (struct sockaddr_in6 *)sa_addr; tst_resm(TINFO, "PEER ADDR %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x PORT %d", NIP6(in6_addr->sin6_addr), ntohs(in6_addr->sin6_port)); addr_buf += sizeof(struct sockaddr_in6); } } sctp_freepaddrs(paddrs); tst_resm(TPASS, "sctp_freepaddrs"); /* Shut down the link. */ close(sk1); /* Get the shutdown complete notification. */ inmessage.msg_controllen = sizeof(incmsg); inmessage.msg_namelen = sizeof(msgname); memset(&msgname, 0, sizeof(msgname)); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); #if TEST_V6 if (inmessage.msg_namelen != sizeof(struct sockaddr_in6)) { DUMP_CORE; } if (msgname.v6.sin6_port != htons(SCTP_TESTPORT_1)) { DUMP_CORE; } if (msgname.v6.sin6_family != AF_INET6) { DUMP_CORE; } if (memcmp(&msgname.v6.sin6_addr, &in6addr_loopback, sizeof(msgname.v6.sin6_addr))) { DUMP_CORE; } #else if (inmessage.msg_namelen != sizeof(struct sockaddr_in)) { DUMP_CORE; } if (msgname.v4.sin_port != htons(SCTP_TESTPORT_1)) { DUMP_CORE; } if (msgname.v4.sin_family != AF_INET) { DUMP_CORE; } if (msgname.v4.sin_addr.s_addr != SCTP_IP_LOOPBACK) { DUMP_CORE; } #endif tst_resm(TPASS, "recvmsg SHUTDOWN_COMP notification"); close(sk2); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_rtoinfo.c0000644000175000017500000000717612300634451024703 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the getsockopt () and sectsockopt () with * SCTP_RTOINFO option on 1-1 style socket * * This program first gets the default values using getsockopt(). It also sets * the value using setsockopt() and gets the set value using getsockopt(). * A comparison between set values and get values are performed. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include /* for sockaddr_in6 */ #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 3; int TST_CNT = 0; int main(void) { int sd, ret; socklen_t len; struct sctp_rtoinfo srtoinfo; /*setting the variables*/ struct sctp_rtoinfo grtoinfo; /*Getting the variables*/ sd = test_socket (PF_INET, SOCK_STREAM, IPPROTO_SCTP); len = sizeof(struct sctp_rtoinfo); /*TEST1 Getting the default values using getsockopt()*/ ret = getsockopt(sd, IPPROTO_SCTP, SCTP_RTOINFO, &grtoinfo, &len); if (ret < 0) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_RTOINFO " "ret:%d, errno:%d", ret, errno); tst_resm(TPASS, "getsockopt() SCTP_RTOINFO - SUCCESS"); /*Assigning the values to RTO initial and max and min bounds*/ srtoinfo.srto_initial=60; srtoinfo.srto_max=100; srtoinfo.srto_min=40; /*TEST2 Setting the values using setsockopt()*/ ret = setsockopt(sd, IPPROTO_SCTP, SCTP_RTOINFO, &srtoinfo, sizeof(struct sctp_rtoinfo)); if (ret < 0) tst_brkm(TBROK, tst_exit, "setsockopt SCTP_RTOINFO " "ret:%d, errno:%d", ret, errno); tst_resm(TPASS, "setsockopt() SCTP_RTOINFO - SUCCESS"); /*Getting the values which are set using setsockopt()*/ ret = getsockopt(sd, IPPROTO_SCTP, SCTP_RTOINFO, &grtoinfo, &len); if (ret < 0) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_RTOINFO " "ret:%d, errno:%d", ret, errno); /* TEST3 Compare the get values with the set values. */ if (srtoinfo.srto_initial != grtoinfo.srto_initial && srtoinfo.srto_max != grtoinfo.srto_max && srtoinfo.srto_min != grtoinfo.srto_min) tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_RTOINFO " "compare failed"); tst_resm(TPASS, "setsockopt()/getsockopt SCTP_RTOINFO compare - " "SUCCESS"); close(sd); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_getname.c0000644000175000017500000002303212300634451023466 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2004 * Copyright (c) 1999-2001 Motorola, 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * * Written or modified by: * Sridhar Samudrala */ /* This is a kernel test to verify getsockname() and getpeername() interfaces * for single-homed one-to-one style sockets. */ #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 13; int TST_CNT = 0; #define MAX_CLIENTS 10 int main(int argc, char *argv[]) { int clt_sk, svr_sk, accept_sk; sockaddr_storage_t svr_loop, accept_loop; sockaddr_storage_t svr_local_addr, svr_peer_addr; sockaddr_storage_t clt_local_addr, clt_peer_addr; socklen_t len; int error; int pf_class; int fd, err_no = 0; char filename[21]; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Initialize the server and client addresses. */ #if TEST_V6 pf_class = PF_INET6; svr_loop.v6.sin6_family = AF_INET6; svr_loop.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_ANY_INIT; svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1); #else pf_class = PF_INET; svr_loop.v4.sin_family = AF_INET; svr_loop.v4.sin_addr.s_addr = INADDR_ANY; svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); #endif /* Create and bind the listening server socket. */ svr_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop)); memset(&svr_local_addr, 0x00, sizeof(svr_local_addr)); len = sizeof(svr_local_addr); /* Verify that getsockname() on an unconnected socket works fine. */ error = getsockname(svr_sk, (struct sockaddr *)&svr_local_addr, &len); if (0 != error) tst_brkm(TBROK, tst_exit, "getsockname: %s", strerror(errno)); tst_resm(TPASS, "getsockname on an unconnected socket"); memset(&svr_peer_addr, 0x00, sizeof(svr_peer_addr)); len = sizeof(svr_peer_addr); /* Verify that getpeername() on an unconnected socket fails. */ error = getpeername(svr_sk, (struct sockaddr *)&svr_peer_addr, &len); if ((-1 != error) || (ENOTCONN != errno)) tst_brkm(TBROK, tst_exit, "getpeername on an unconnected " "socket error:%d, errno:%d", error, errno); tst_resm(TPASS, "getpeername on an unconnected socket"); /* Mark svr_sk as being able to accept new associations. */ test_listen(svr_sk, 5); /* Create the client socket. */ clt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /* Do a blocking connect from clt_sk to svr_sk */ #if TEST_V6 svr_loop.v6.sin6_addr = in6addr_loopback; #else svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; #endif test_connect(clt_sk, &svr_loop.sa, sizeof(svr_loop)); memset(&clt_local_addr, 0x00, sizeof(clt_local_addr)); len = sizeof(clt_local_addr); /* Get the client's local address. */ error = getsockname(clt_sk, (struct sockaddr *)&clt_local_addr, &len); if (0 != error) tst_brkm(TBROK, tst_exit, "getsockname on a connected client " "socket: %s", strerror(errno)); tst_resm(TPASS, "getsockname on a connected client socket"); memset(&clt_peer_addr, 0x00, sizeof(clt_peer_addr)); len = sizeof(clt_peer_addr); /* Get the client's peer address. */ error = getpeername(clt_sk, (struct sockaddr *)&clt_peer_addr, &len); if (0 != error) tst_brkm(TBROK, tst_exit, "getpeername on a connected client " "socket: %s", strerror(errno)); tst_resm(TPASS, "getpeername on a connected client socket"); /* Extract the association on the listening socket as a new socket. */ len = sizeof(accept_loop); accept_sk = test_accept(svr_sk, &accept_loop.sa, &len); memset(&svr_local_addr, 0x00, sizeof(svr_local_addr)); len = sizeof(svr_local_addr); /* Get the server's local address. */ error = getsockname(accept_sk, (struct sockaddr *)&svr_local_addr, &len); if (0 != error) tst_brkm(TBROK, tst_exit, "getsockname on a connected server " "socket: %s", strerror(errno)); tst_resm(TPASS, "getsockname on a connected server socket"); memset(&svr_peer_addr, 0x00, sizeof(svr_peer_addr)); len = sizeof(svr_peer_addr); /* Get the server's peer address. */ error = getpeername(accept_sk, (struct sockaddr *)&svr_peer_addr, &len); if (0 != error) tst_brkm(TBROK, tst_exit, "getpeername on a connected server " "socket: %s", strerror(errno)); tst_resm(TPASS, "getpeername on a connected server socket"); if (svr_local_addr.v4.sin_port != clt_peer_addr.v4.sin_port) tst_brkm(TBROK, tst_exit, "Server's local port(%d) doesn't " "match Client's peer port(%d)\n", svr_local_addr.v4.sin_port, clt_peer_addr.v4.sin_port); if (svr_peer_addr.v4.sin_port != clt_local_addr.v4.sin_port) tst_brkm(TBROK, tst_exit, "Server's peer port(%d) doesn't " "match Client's local port(%d)\n", svr_peer_addr.v4.sin_port, clt_local_addr.v4.sin_port); #if TEST_V6 if (memcmp(&svr_local_addr, &clt_peer_addr, len) != 0) tst_brkm(TBROK, tst_exit, "Server's local address and client's " "peer addresses do not match\n"); if (memcmp(&svr_peer_addr, &clt_local_addr, len) != 0) tst_brkm(TBROK, tst_exit, "Server's peer address and client's " "local addresses do not match\n"); #else if (svr_local_addr.v4.sin_addr.s_addr != clt_peer_addr.v4.sin_addr.s_addr) tst_brkm(TBROK, tst_exit, "Server's local address and client's " "peer addresses do not match\n"); if (svr_peer_addr.v4.sin_addr.s_addr != clt_local_addr.v4.sin_addr.s_addr) tst_brkm(TBROK, tst_exit, "Server's peer address and client's " "local addresses do not match\n"); #endif tst_resm(TPASS, "getsockname/getpeername server/client match"); memset(&clt_local_addr, 0x00, sizeof(clt_local_addr)); len = sizeof(clt_local_addr); /*getsockname(): Bad socket descriptor, EBADF expected error*/ error = getsockname(-1, (struct sockaddr *)&clt_local_addr, &len); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "getsockname on a bad socket " "descriptor. error:%d errno:%d", error, errno); tst_resm(TPASS, "getsockname on a bad socket descriptor - EBADF"); /*getsockname(): Invalid socket, ENOTSOCK expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = getsockname(fd, (struct sockaddr *)&clt_local_addr, &len); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "getsockname on an invalid socket " "error:%d errno:%d", error, err_no); tst_resm(TPASS, "getsockname on an invalid socket - ENOTSOCK"); /*getsockname(): Invalid structure, EFAULT expected error*/ error = getsockname(clt_sk, (struct sockaddr *)-1, &len); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "getsockname with invalid buffer " "error:%d errno:%d", error, errno); tst_resm(TPASS, "getsockname with invalid buffer - EFAULT"); memset(&clt_peer_addr, 0x00, sizeof(clt_peer_addr)); len = sizeof(clt_peer_addr); /*getpeername(): Bad socket descriptor, EBADF expected error*/ error = getpeername(-1, (struct sockaddr *)&clt_local_addr, &len); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "getpeername on a bad socket " "descriptor. error:%d errno:%d", error, errno); tst_resm(TPASS, "getpeername on a bad socket descriptor - EBADF"); /*getpeername(): Invalid socket, ENOTSOCK expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = getpeername(fd, (struct sockaddr *)&clt_local_addr, &len); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "getpeername on an invalid socket " "error:%d errno:%d", error, err_no); tst_resm(TPASS, "getpeername on an invalid socket - ENOTSOCK"); /*getpeername(): Invalid structure, EFAULT expected error*/ error = getpeername(clt_sk, (struct sockaddr *)-1, &len); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "getpeername with invalid buffer " "error:%d errno:%d", error, errno); tst_resm(TPASS, "getpeername with invalid buffer - EFAULT"); close(clt_sk); close(svr_sk); close(accept_sk); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_fragments.c0000644000175000017500000002343612300634451024044 0ustar michaelmichael/* 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 * * 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: * La Monte H.P. Yarroll * Karl Knutson * Hui Huang * Jon Grimm * Sridhar Samudrala */ /* This is a functional test to verify the data fragmentation, reassembly * support and SCTP_DISABLE_FRAGMENTS socket option. * The following tests are done in sequence. * - Verify SCTP_DISABLE_FRAGMENTS socket option by doing a setsockopt() * followed by a getsockopt(). * - Verify that a message size exceeding the association fragmentation * point cannot be sent when fragmentation is disabled. * - Send and receive a set of messages that are bigger than the path mtu. * The different message sizes to be tested are specified in the array * msg_sizes[]. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 4; int TST_CNT = 0; int msg_sizes[] = {1353, 2000, 5000, 10000, 20000, 32768}; 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, bytes_sent; int pf_class; uint32_t ppid; uint32_t stream; char *big_buffer; int msg_len, msg_cnt, i; void *msg_buf; int disable_frag; socklen_t optlen; /* 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; 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; 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); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(sk1); test_enable_assoc_change(sk2); /* Bind these sockets to the test ports. */ test_bind(sk1, &loop1.sa, sizeof(loop1)); test_bind(sk2, &loop2.sa, sizeof(loop2)); /* 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; msg_len = 10; msg_buf = test_build_msg(10); outmessage.msg_iov->iov_base = msg_buf; outmessage.msg_iov->iov_len = msg_len; test_sendmsg(sk1, &outmessage, 0, msg_len); /* 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); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; associd2 = sac->sac_assoc_id; #endif /* 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); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; associd1 = sac->sac_assoc_id; #endif /* Get the first message which was sent. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, msg_len, MSG_EOR, stream, ppid); free(msg_buf); /* Disable fragmentation. */ disable_frag = 1; test_setsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag, sizeof(disable_frag)); tst_resm(TPASS, "setsockopt(SCTP_DISABLE_FRAGMENTS)"); /* Do a getsockopt() and verify that fragmentation is disabled. */ disable_frag = 0; optlen = sizeof(disable_frag); error = test_getsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag, &optlen); if ((error != 0) && (disable_frag != 1)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DISABLE_FRAGMENTS) " "error:%d errno:%d disable_frag:%d", error, errno, disable_frag); tst_resm(TPASS, "getsockopt(SCTP_DISABLE_FRAGMENTS)"); /* Try to send a messsage that exceeds association fragmentation point * and verify that it fails. */ msg_len = 100000; msg_buf = test_build_msg(msg_len); outmessage.msg_iov->iov_base = msg_buf; outmessage.msg_iov->iov_len = msg_len; error = sendmsg(sk1, &outmessage, 0); if ((error != -1) || (errno != EMSGSIZE)) tst_brkm(TBROK, tst_exit, "Send a message that exceeds " "assoc frag point error:%d errno:%d", error, errno); tst_resm(TPASS, "Send a message that exceeds assoc frag point"); /* Enable Fragmentation. */ disable_frag = 0; test_setsockopt(sk1, SCTP_DISABLE_FRAGMENTS, &disable_frag, sizeof(disable_frag)); msg_cnt = sizeof(msg_sizes) / sizeof(int); /* Send and receive the messages of different sizes specified in the * msg_sizes array in a loop. */ for (i = 0; i < msg_cnt; i++) { msg_len = msg_sizes[i]; msg_buf = test_build_msg(msg_len); outmessage.msg_iov->iov_base = msg_buf; outmessage.msg_iov->iov_len = msg_len; bytes_sent = test_sendmsg(sk1, &outmessage, 0, msg_len); tst_resm(TINFO, "Sent %d byte message", bytes_sent); inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); /* Handle Partial Reads. */ if (inmessage.msg_flags & MSG_EOR) { test_check_msg_data(&inmessage, error, bytes_sent, MSG_EOR, stream, ppid); tst_resm(TINFO, "Received %d byte message", error); } else { int remain; test_check_msg_data(&inmessage, error, error, 0, stream, ppid); tst_resm(TINFO, "Received %d byte message", error); /* Read the remaining message. */ inmessage.msg_controllen = sizeof(incmsg); remain = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, remain, bytes_sent - error, MSG_EOR, stream, ppid); tst_resm(TINFO, "Received %d byte message", error); } free(msg_buf); } tst_resm(TPASS, "Send/Receive fragmented messages"); /* 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; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_shutdown.c0000644000175000017500000001607412300634451025073 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the shutdown() call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: shutdown with SHUT_WR flag to disable new send * TEST4: shutdown with SHUT_RD flag to disable new receive * TEST5: shutdown with SHUT_RDWR flag to disable new receive/send * TEST6: Unconnected socket * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 6; int TST_CNT = 0; #define MAX_CLIENTS 10 int main(int argc, char *argv[]) { int clnt_sk[MAX_CLIENTS], acpt_sk[MAX_CLIENTS],sk; int lstn_sk; struct sockaddr_in lstn_addr, acpt_addr; socklen_t addrlen; int error, i; char *message = "hello, world!\n"; char msgbuf[100]; int pf_class; int fd, err_no = 0; char filename[21]; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); /* Initialize the server and client addresses. */ pf_class = PF_INET; lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); test_listen(lstn_sk, MAX_CLIENTS); for (i = 0; i < MAX_CLIENTS; i++) { clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_connect(clnt_sk[i], (struct sockaddr *)&lstn_addr, sizeof(lstn_addr)); } for (i = 0; i < MAX_CLIENTS; i++) { addrlen = sizeof(acpt_addr); acpt_sk[i] = test_accept(lstn_sk, (struct sockaddr *)&acpt_addr, &addrlen); } /*shutdown() TEST1: Bad socket descriptor, EBADF Expected error*/ error = shutdown(-1, SHUT_WR); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "shutdown with a bad socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "shutdown() with a bad socket descriptor - EBADF"); /*shutdown() TEST2: Invalid socket, ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = shutdown(fd, SHUT_WR); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "shutdown with an invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "shutdown() with an invalid socket - ENOTSOCK"); errno = 0; /*Do a send first before doing shutdown*/ test_send(acpt_sk[0], message, strlen(message), 0); /*shutdown() TEST3: shutdown with SHUT_WR flag to disable new send*/ error = shutdown(clnt_sk[0], SHUT_WR); if (error < 0) tst_brkm(TBROK, tst_exit, "shutdown with SHUT_WR flag " "error:%d, errno:%d", error, errno); /* Reading on a socket that has received SHUTDOWN should return 0 * indicating EOF. */ error = recv(acpt_sk[0], msgbuf, 100, 0); if ((error != 0) || (errno != 0)) tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN received socket " "error:%d, errno:%d", error, errno); /* Read the pending message on clnt_sk[0] that was received before * SHUTDOWN call. */ test_recv(clnt_sk[0], msgbuf, 100, 0); /* No more messages and the association is SHUTDOWN, should fail. */ error = recv(clnt_sk[0], msgbuf, 100, 0); if ((error != -1) || (errno != ENOTCONN)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_WR socket with no " "messages error:%d, errno:%d", error, errno); tst_resm(TPASS, "shutdown() with SHUT_WR flag - SUCCESS"); errno = 0; /*shutdown() TEST4: shutdown with SHUT_RD flag to disable new receive*/ test_shutdown(clnt_sk[1], SHUT_RD); error = recv(clnt_sk[1], msgbuf, 100, 0); if ((error != 0) || (errno != 0)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket " "error:%d, errno:%d", error, errno); /* Sending a message on SHUT_RD socket. */ error = test_send(clnt_sk[1], message, strlen(message), 0); if (error < 0) tst_brkm(TBROK, tst_exit, "send on a SHUT_RD socket " "error:%d, errno:%d", error, errno); /* Receive the message sent on SHUT_RD socket. */ test_recv(acpt_sk[1], msgbuf, 100, 0); /* Send a message to the SHUT_RD socket. */ test_send(acpt_sk[1], message, strlen(message), 0); /* We should not receive the message as the socket is SHUT_RD */ error = recv(clnt_sk[1], msgbuf, 100, 0); if ((error != 0) || (errno != 0)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "shutdown() with SHUT_RD flag - SUCCESS"); /*shutdown() TEST5: shutdown with SHUT_RDWR flag to disable new receive/send*/ test_shutdown(clnt_sk[2], SHUT_RDWR); error = recv(acpt_sk[2], msgbuf, 100, 0); if ((error != 0) || (errno != 0)) tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN received socket " "error:%d, errno:%d", error, errno); error = recv(clnt_sk[2], msgbuf, 100, 0); if ((error != 0) || (errno != 0)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RDWR socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "shutdown() with SHUT_RDWR flag - SUCCESS"); /*shutdown() TEST6: Unconnected socket, ENOTCONN Expected error*/ error = shutdown(sk, SHUT_RD); if ((error != -1) || (errno != ENOTCONN)) tst_brkm(TBROK, tst_exit, "shutdown on an unconnected socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "shutdown() on an unconnected socket - SUCCESS"); for (i = 0; i < MAX_CLIENTS; i++) close(clnt_sk[i]); for (i = 0; i < MAX_CLIENTS; i++) close(acpt_sk[i]); close(lstn_sk); close(sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_assoc_abort.c0000644000175000017500000001752312300634451024355 0ustar michaelmichael/* 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 * * 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: * Ardelle Fan * Sridhar Samudrala */ /* This is a functional test to verify the ungraceful abort of an * association. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; #define MAX_CLIENTS 10 int main(int argc, char *argv[]) { int svr_sk, clt_sk[MAX_CLIENTS]; sockaddr_storage_t svr_loop, clt_loop[MAX_CLIENTS]; sctp_assoc_t svr_associd[MAX_CLIENTS]; 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; uint32_t ppid; uint32_t stream; struct sctp_assoc_change *sac; char *big_buffer; int i; char *message = "hello, world!\n"; struct sctp_status status; socklen_t status_len; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Create and bind the server socket. */ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); svr_loop.v4.sin_family = AF_INET; svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop)); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(svr_sk); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 1); /* Create and bind all the client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { clt_sk[i] = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); clt_loop[i].v4.sin_family = AF_INET; clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i); test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i])); test_enable_assoc_change(clt_sk[i]); } /* Build up a msghdr structure we can use for all sending. */ outmessage.msg_name = &svr_loop; outmessage.msg_namelen = sizeof(svr_loop); 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; out_iov.iov_base = message; out_iov.iov_len = strlen(message) + 1; /* Send the first message from all the clients to the server. This * will create the associations. */ for (i = 0; i < MAX_CLIENTS; i++) test_sendmsg(clt_sk[i], &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 all client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); } /* Get the communication up message and the data message on the * server sockets for all the clients. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); sac = (struct sctp_assoc_change *)iov.iov_base; svr_associd[i] = sac->sac_assoc_id; } outmessage.msg_name = NULL; outmessage.msg_namelen = 0; outmessage.msg_iov = NULL; outmessage.msg_iovlen = 0; 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)); sinfo->sinfo_flags |= SCTP_ABORT; /* Shutdown all the associations of the server socket in a loop. */ for (i = 0; i < MAX_CLIENTS; i++) { sinfo->sinfo_assoc_id = svr_associd[i]; /* Verify that the association is present. */ memset(&status, 0, sizeof(struct sctp_status)); status.sstat_assoc_id = sinfo->sinfo_assoc_id; status_len = sizeof(struct sctp_status); error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS, &status, &status_len); if (error) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS): %s", strerror(errno)); /* Call sendmsg() to abort the association. */ test_sendmsg(svr_sk, &outmessage, 0, 0); /* Verify that the association is no longer present. */ memset(&status, 0, sizeof(struct sctp_status)); status.sstat_assoc_id = sinfo->sinfo_assoc_id; status_len = sizeof(struct sctp_status); error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS, &status, &status_len); if ((error != -1) && (errno != EINVAL)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) " "error:%d errno:%d", error, errno); } close(svr_sk); /* Get the COMM_LOST notification. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change)+4, SCTP_ASSOC_CHANGE, SCTP_COMM_LOST); close(clt_sk[i]); } tst_resm(TPASS, "ABORT an association using SCTP_ABORT"); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_connectx.c0000644000175000017500000002301512300634451023670 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2002, 2003 * Copyright (c) 1999-2001 Motorola, 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * * Written or modified by: * Sridhar Samudrala */ /* This is a kernel test to verify the one-to-many style sctp_connectx() * in blocking and non-blocking modes. */ #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 9; int TST_CNT = 0; #define NUMADDR 6 #define SCTP_IP_LOOPBACK_I(I) htonl(0x7f000001 + I) #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] int main(int argc, char *argv[]) { int svr_sk, clt_sk1, clt_sk2, peeloff_sk; sctp_assoc_t associd, svr_associd1, svr_associd2, clt_associd1, clt_associd2; struct iovec iov; struct msghdr inmessage; int error, i; struct sctp_assoc_change *sac; char *big_buffer; int flags; struct sockaddr_in svr_loop[NUMADDR]; struct sockaddr_in svr_try[NUMADDR]; struct sockaddr_in clt_loop1[NUMADDR]; struct sockaddr_in clt_loop2[NUMADDR]; struct sockaddr_in clt_loop3[NUMADDR]; sockaddr_storage_t svr_test[NUMADDR], clt_test1[NUMADDR], clt_test2[NUMADDR]; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); for (i = 0; i < NUMADDR; i++) { /* Initialize the server and client addresses. */ svr_loop[i].sin_family = AF_INET; svr_loop[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); svr_loop[i].sin_port = htons(SCTP_TESTPORT_1); svr_test[i].v4.sin_family = AF_INET; svr_test[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); svr_test[i].v4.sin_port = htons(SCTP_TESTPORT_1); svr_try[i].sin_family = AF_INET; if (i < (NUMADDR-1)) { svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i); } else { /* Make last address invalid. */ svr_try[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x400); } svr_try[i].sin_port = htons(SCTP_TESTPORT_1); clt_loop1[i].sin_family = AF_INET; clt_loop1[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100); clt_loop1[i].sin_port = htons(SCTP_TESTPORT_2); clt_test1[i].v4.sin_family = AF_INET; clt_test1[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x100); clt_test1[i].v4.sin_port = htons(SCTP_TESTPORT_2); clt_loop2[i].sin_family = AF_INET; clt_loop2[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200); clt_loop2[i].sin_port = htons(SCTP_TESTPORT_2+1); clt_test2[i].v4.sin_family = AF_INET; clt_test2[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x200); clt_test2[i].v4.sin_port = htons(SCTP_TESTPORT_2+1); clt_loop3[i].sin_family = AF_INET; clt_loop3[i].sin_addr.s_addr = SCTP_IP_LOOPBACK_I(i + 0x300); clt_loop3[i].sin_port = htons(SCTP_TESTPORT_2+2); } /* Create and bind the server socket. */ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(svr_sk, (struct sockaddr *)&svr_loop[0], sizeof(svr_loop[0])); test_bindx_add(svr_sk, (struct sockaddr *)&svr_loop[1], NUMADDR-1); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 1); /* Create and bind the client sockets. */ clt_sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(clt_sk1, (struct sockaddr *)&clt_loop1[0], sizeof(clt_loop1)); test_bindx_add(clt_sk1, (struct sockaddr *)&clt_loop1[1], NUMADDR-1); clt_sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(clt_sk2, (struct sockaddr *)&clt_loop2[0], sizeof(clt_loop2)); test_bindx_add(clt_sk2, (struct sockaddr *)&clt_loop2[1], NUMADDR-1); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(svr_sk); test_enable_assoc_change(clt_sk1); test_enable_assoc_change(clt_sk2); /* Set clt_sk1 as non-blocking. */ flags = fcntl(clt_sk1, F_GETFL, 0); if (flags < 0) tst_brkm(TBROK, tst_exit, "fcntl F_GETFL: %s", strerror(errno)); if (fcntl(clt_sk1, F_SETFL, flags | O_NONBLOCK) < 0) tst_brkm(TBROK, tst_exit, "fcntl F_SETFL: %s", strerror(errno)); /* Do a non-blocking connectx from clt_sk1 to svr_sk */ error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR, &associd); /* Non-blocking connectx should return immediately with EINPROGRESS. */ if ((error != -1) || (EINPROGRESS != errno)) tst_brkm(TBROK, tst_exit, "non-blocking connectx error: %d" "errno:%d", error, errno); tst_resm(TPASS, "non-blocking connectx"); /* Doing a connectx on a socket to create an association that is * is already established should return EISCONN. */ error = sctp_connectx(clt_sk1, (struct sockaddr *)svr_try, NUMADDR, NULL); if ((error != -1) || (EISCONN != errno)) tst_brkm(TBROK, tst_exit, "connectx on a socket to create an " "assoc that is already established error:%d errno:%d", error, errno); tst_resm(TPASS, "connectx on a socket to create an assoc that is " "already established"); /* Initialize inmessage for all receives. */ memset(&inmessage, 0, sizeof(inmessage)); big_buffer = test_malloc(REALLY_BIG); iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = NULL; /* Get COMM_UP on clt_sk1 */ error = test_recvmsg(clt_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; clt_associd1 = sac->sac_assoc_id; if (associd) { if (associd != clt_associd1) tst_brkm(TBROK, tst_exit, "Association id mismatch: " "connectx returned %d, notification returned:%d", associd, clt_associd1); tst_resm(TPASS, "Association id match between sctp_connectx()" " and notification."); } /* Get COMM_UP on svr_sk */ error = test_recvmsg(svr_sk, &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; svr_associd1 = sac->sac_assoc_id; /* Do a blocking connectx from clt_sk2 to svr_sk. * Blocking connectx should block until the association is established * and return success. */ test_connectx(clt_sk2, (struct sockaddr *)svr_try, NUMADDR); /* Get COMM_UP on clt_sk2 */ error = test_recvmsg(clt_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; clt_associd2 = sac->sac_assoc_id; /* Get COMM_UP on svr_sk */ error = test_recvmsg(svr_sk, &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; svr_associd2 = sac->sac_assoc_id; tst_resm(TPASS, "blocking connectx"); peeloff_sk = test_sctp_peeloff(svr_sk, svr_associd1); /* Doing a connectx on a peeled off socket should fail. */ error = sctp_connectx(peeloff_sk, (struct sockaddr *)clt_loop3, NUMADDR, NULL); if ((error != -1) || (EISCONN != errno)) tst_brkm(TBROK, tst_exit, "connectx on a peeled off socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connectx on a peeled off socket"); /* Trying to create an association on a socket that matches an * existing peeled-off association should fail. */ error = sctp_connectx(svr_sk, (struct sockaddr *)clt_loop1, NUMADDR, NULL); if ((error != -1) || (EADDRNOTAVAIL != errno)) tst_brkm(TBROK, tst_exit, "connectx to create an assoc that " "matches a peeled off assoc error:%d errno:%d", error, errno); tst_resm(TPASS, "connectx to create an assoc that matches a peeled off " "assoc"); test_peer_addr(peeloff_sk, svr_associd1, clt_test1, NUMADDR); tst_resm(TPASS, "server association 1 peers ok"); test_peer_addr(svr_sk, svr_associd2, clt_test2, NUMADDR); tst_resm(TPASS, "server association 2 peers ok"); test_peer_addr(clt_sk1, clt_associd1, svr_test, NUMADDR); tst_resm(TPASS, "client association 1 peers ok"); test_peer_addr(clt_sk2, clt_associd2, svr_test, NUMADDR); tst_resm(TPASS, "client association 2 peers ok"); close(svr_sk); close(clt_sk1); close(clt_sk2); close(peeloff_sk); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_autoclose.c0000644000175000017500000001246312300634451024052 0ustar michaelmichael/* 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 * * 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: * Sridhar Samudrala */ /* This is a Functional Test to verify autoclose functionality and the * socket option SCTP_AUTOCLOSE that can be used to specify the duration in * which an idle association is automatically closed. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; int main(int argc, char *argv[]) { int sk1, sk2; sockaddr_storage_t loop1, loop2; struct msghdr inmessage, outmessage; struct iovec iov, out_iov; int error; char *big_buffer; char *message = "hello, world!\n"; uint32_t autoclose; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); 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); /* Create the two endpoints which will talk to each other. */ sk1 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); sk2 = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(sk1); test_enable_assoc_change(sk2); /* Bind these sockets to the test ports. */ test_bind(sk1, &loop1.sa, sizeof(loop1)); test_bind(sk2, &loop2.sa, sizeof(loop2)); /* Mark sk2 as being able to accept new associations. */ test_listen(sk2, 1); /* Set the autoclose duration for the associations created on sk1 * and sk2 to be 5 seconds. */ autoclose = 5; test_setsockopt(sk1, SCTP_AUTOCLOSE, &autoclose, sizeof(autoclose)); test_setsockopt(sk2, SCTP_AUTOCLOSE, &autoclose, sizeof(autoclose)); /* Send the first message. This will create the association. */ memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &loop2; outmessage.msg_namelen = sizeof(loop2); outmessage.msg_iov = &out_iov; outmessage.msg_iovlen = 1; 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 = NULL; /* Get the communication up message on sk2. */ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); /* Get the communication up message on sk1. */ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); /* Get the first message which was sent. */ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR|MSG_CTRUNC, 0, 0); tst_resm(TINFO, "Waiting for the associations to close automatically " "in 5 secs"); /* Get the shutdown complete notification from sk1. */ error = test_recvmsg(sk1, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); /* Get the shutdown complete notification from sk2. */ error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); tst_resm(TPASS, "Autoclose of associations"); /* Shut down the link. */ close(sk1); close(sk2); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_send.c0000644000175000017500000001667212300634451024155 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the send() call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: On a listening socket * TEST4: On a closed association * TEST5: Invalid message address * TEST6: send from client to server * TEST7: send from server to client * TEST8: sending partial data from a buffer * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 8; int TST_CNT = 0; int main(int argc, char *argv[]) { socklen_t len,len_snd; int msg_count; int sk,sk1,pf_class,lstn_sk,acpt_sk,acpt1_sk, flag, count; char *message = "hello, world!\n"; char *message_rcv; int fd, err_no = 0; char filename[21]; struct sockaddr_in conn_addr,lstn_addr,svr_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); len_snd = (strlen(message) + 1); flag = MSG_NOSIGNAL; /*send () TEST1: Bad socket descriptor, EBADF Expected error*/ count = send(-1, message, len_snd, flag); if (count != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "send with a bad socket " "descriptor count:%d, errno:%d", count, errno); tst_resm(TPASS, "send() with a bad socket descriptor - EBADF"); /*send () TEST2: Invalid socket, ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); count = send(fd, message, len_snd, flag); if (count == -1) err_no = errno; close(fd); unlink(filename); if (count != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "send with invalid socket " "count:%d, errno:%d", count, err_no); tst_resm(TPASS, "send() with invalid socket - ENOTSOCK"); /*send () TEST3: send on listening socket, EPIPE Expected error*/ count = send(lstn_sk, message, len_snd, flag); if (count != -1 || errno != EPIPE) tst_brkm(TBROK, tst_exit, "send on a listening socket " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "send() on a listening socket - EPIPE"); #if 0 /*send () TEST4: Invalid message address, EFAULT Expected error*/ /* FIXME this test should pass. Don't catch why... */ count = send(sk, (char *)0x1, len_snd, flag); if (count != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "send with invalid message " "pointer count:%d, errno:%d", count, errno); tst_resm(TPASS, "send() with invalid message ptr - EFAULT"); #endif test_connect(sk1, (struct sockaddr *) &lstn_addr, len); count = test_send(sk1, message, len_snd, flag); close(sk1); acpt1_sk = test_accept(lstn_sk, (struct sockaddr *)&conn_addr, &len); /*send () TEST5: send on closed association, EPIPE Expected error*/ count = send(acpt1_sk, message, len_snd, flag); if (count != -1 || errno != EPIPE) tst_brkm(TBROK, tst_exit, "send on a closed association " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "send() on a closed association - EPIPE"); close(acpt1_sk); close(sk); close(lstn_sk); close(acpt_sk); sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); message_rcv = malloc(512); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); len = sizeof(struct sockaddr_in); test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); msg_count = strlen(message) + 1; /*send() TEST6: Sending data from client socket to server socket*/ count = send(sk, message, msg_count, flag); if (count != msg_count) tst_brkm(TBROK, tst_exit, "send from client to server " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "send() from client to server - SUCCESS"); test_recv(acpt_sk, message_rcv, msg_count, flag); strncpy(message_rcv,"\0",512); /*send() TEST7: Sending data from accept socket to client socket*/ count = send(acpt_sk, message, msg_count, flag); if (count != msg_count) tst_brkm(TBROK, tst_exit, "send from accept socket to client " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "send() from accept socket to client - SUCCESS"); test_recv(sk, message_rcv, msg_count, flag); /*send() TEST8: Sending less number of data from the buffer*/ /*Sending only 5 bytes so that only hello is received*/ test_send(sk, message, 5 , flag); test_recv(acpt_sk, message_rcv, 5, flag); tst_resm(TPASS, "send() partial data from a buffer - SUCCESS"); /* TEST9: sctp_send with no sinfo */ test_sctp_send(sk, message, strlen(message) + 1 , NULL, flag); test_recv(acpt_sk, message_rcv, strlen(message) + 1, flag); tst_resm(TPASS, "sctp_send() with no sinfo - SUCCESS"); close(sk1); close(lstn_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_recvmsg.c0000644000175000017500000001562112300634451024663 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the recvmsg() call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: Invalid iovec pointer * TEST4: Invalid msghdr pointer * TEST5: On a listening socket * TEST6: Reading on a socket that received SHUTDOWN * TEST7: Reading the pending message socket that received SHUTDOWN * TEST8: No more message and association is shutdown * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 8; int TST_CNT = 0; int main(int argc, char *argv[]) { socklen_t len; int sk,pf_class,lstn_sk,acpt_sk; int flag = 0; int fd, err_no = 0; char filename[21]; struct msghdr inmessage; char *message = "hello, world!\n"; struct iovec iov_rcv; int count; char * buffer_rcv; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; char *message1 = "hello, world!\n"; struct sockaddr_in conn_addr,lstn_addr,svr_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); memset(&inmessage, 0, sizeof(inmessage)); buffer_rcv = malloc(REALLY_BIG); iov_rcv.iov_base = buffer_rcv; iov_rcv.iov_len = REALLY_BIG; inmessage.msg_iov = &iov_rcv; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); /*recvmsg () TEST1: Bad socket descriptor, EBADF Expected error*/ count = recvmsg(-1, &inmessage, flag); if (count != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "recvmsg with a bad socket " "descriptor count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvmsg() with a bad socket descriptor - EBADF"); /*recvmsg () TEST2: Invalid socket , ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); count = recvmsg(fd, &inmessage, flag); if (count == -1) err_no = errno; close(fd); unlink(filename); if (count != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "recvmsg with invalid socket " "count:%d, errno:%d", count, err_no); tst_resm(TPASS, "recvmsg() with invalid socket - ENOTSOCK"); /*recvmsg () TEST3: Invalid iovec pointer EFAULT, Expected error*/ inmessage.msg_iov = (struct iovec *)-1; count = recvmsg(acpt_sk, &inmessage, flag); if (count != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "recvmsg with invalid iovec " "pointer count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvmsg() with invalid iovec ptr - EFAULT"); inmessage.msg_iov = &iov_rcv; /*recvmsg () TEST4: Invalid msghdr pointer EFAULT, Expected error*/ count = recvmsg(acpt_sk, (struct msghdr *)-1, flag); if (count != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "recvmsg with invalid msghdr " "pointer count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvmsg() with invalid msghdr ptr - EFAULT"); /*recvmsg () TEST5:recvmsg on listening socket,ENOTCONN Expected error*/ count = recvmsg(lstn_sk, &inmessage, flag); if (count != -1 || errno != ENOTCONN) tst_brkm(TBROK, tst_exit, "recvmsg on listening socket " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvmsg() on listening socket - ENOTCONN"); count = test_send(acpt_sk, message1, strlen(message), 0); test_shutdown(sk, SHUT_WR); flag = MSG_NOSIGNAL; /*recvmsg () TEST6:reading on a socket that received SHUTDOWN*/ count = recvmsg(acpt_sk, &inmessage, flag); if (count < 0) tst_brkm(TBROK, tst_exit, "recvmsg on a socket that has " "received shutdown count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvmsg() on a socket that has received shutdown - " "EOF"); /*recvmsg () TEST7:reading the pending message socket that sent SHUTDOWN*/ count = recvmsg(sk, &inmessage, flag); if (count < 0) tst_brkm(TBROK, tst_exit, "recvmsg on a socket with pending " "message that has sent shutdown count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvmsg() on a socket with pending message that has " "sent shutdown - SUCCESS"); /*recvmsg () TEST8: No more message and association is shutdown, ENOTCONN Expected error*/ count = recvmsg(sk, &inmessage, flag); if (count != -1 || errno != ENOTCONN) tst_brkm(TBROK, tst_exit, "recvmsg on a socket with no " "pending messages and has sent shutdown count:%d, " "errno:%d", count, errno); tst_resm(TPASS, "recvmsg() on a socket with no pending messages and " " has sent shutdown - ENOTCONN"); close(sk); close(lstn_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_inaddr_any.c0000644000175000017500000002076712300634451024172 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2002, 2003 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * * 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 * * 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: * La Monte H.P. Yarroll * Karl Knutson * Jon Grimm * Sridhar Samudrala * Daisy Chang */ /* This is a functional test to verify binding a socket with INADDRY_ANY * address and send messages. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 2; int TST_CNT = 0; int main(void) { int sk1, sk2; sockaddr_storage_t loop; sockaddr_storage_t anyaddr; 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; struct iovec iov; struct msghdr inmessage; char *message = "hello, world!\n"; char *telephone = "Watson, come here! I need you!\n"; char *telephone_resp = "I already brought your coffee...\n"; int error; int pf_class; uint32_t ppid; uint32_t stream; socklen_t namelen; /* 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; loop.v6.sin6_family = AF_INET6; loop.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_LOOPBACK_INIT; loop.v6.sin6_port = 0; anyaddr.v6.sin6_family = AF_INET6; anyaddr.v6.sin6_addr = (struct in6_addr)SCTP_IN6ADDR_ANY_INIT; anyaddr.v6.sin6_port = 0; #else pf_class = PF_INET; loop.v4.sin_family = AF_INET; loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; loop.v4.sin_port = 0; anyaddr.v4.sin_family = AF_INET; anyaddr.v4.sin_addr.s_addr = INADDR_ANY; anyaddr.v4.sin_port = 0; #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); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(sk1); test_enable_assoc_change(sk2); /* Bind these sockets to the test ports. */ test_bind(sk1, &loop.sa, sizeof(loop)); test_bind(sk2, &anyaddr.sa, sizeof(anyaddr)); tst_resm(TPASS, "bind INADDR_ANY address"); /* Mark sk2 as being able to accept new associations */ test_listen(sk2, 1); /* Now use getsockaname() to retrieve the ephmeral ports. */ namelen = sizeof(loop); error = getsockname(sk1, &loop.sa, &namelen); if (error != 0) tst_brkm(TBROK, tst_exit, "getsockname: %s", strerror(errno)); namelen = sizeof(anyaddr); error = getsockname(sk2, &anyaddr.sa, &namelen); if (error != 0) tst_brkm(TBROK, tst_exit, "getsockname: %s", strerror(errno)); #if TEST_V6 loop.v6.sin6_port = anyaddr.v6.sin6_port; #else loop.v4.sin_port = anyaddr.v4.sin_port; #endif /* Send the first message. This will create the association. */ outmessage.msg_name = &loop; outmessage.msg_namelen = sizeof(loop); 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. */ memset(&inmessage, 0, sizeof(inmessage)); iov.iov_base = test_malloc(REALLY_BIG); 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); /* 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); /* Get the first 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); /* Send 2 messages. */ outmessage.msg_name = &loop; outmessage.msg_namelen = sizeof(loop); 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; outmessage.msg_iov->iov_base = telephone; outmessage.msg_iov->iov_len = strlen(telephone) + 1; test_sendmsg(sk1, &outmessage, 0, strlen(telephone)+1); outmessage.msg_iov->iov_base = telephone_resp; outmessage.msg_iov->iov_len = strlen(telephone_resp) + 1; test_sendmsg(sk1, &outmessage, 0, strlen(telephone_resp)+1); /* Get those two messages. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(telephone) + 1, MSG_EOR, stream, ppid); inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(sk2, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(telephone_resp) + 1, MSG_EOR, stream, ppid); /* 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); tst_resm(TPASS, "send msgs from a socket with INADDR_ANY bind address"); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_connectx.c0000644000175000017500000001732312300634451025037 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the sctp_connectx () call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: Invalid address * TEST4: Invalid address length * TEST5: Invalid address family * TEST6: Valid blocking sctp_connectx * TEST7: Connect when accept queue is full * TEST8: On a listening socket * TEST9: On established socket * TEST10: Connect to re-establish a closed association. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include "sctputil.h" char *TCID = __FILE__; int TST_TOTAL = 10; int TST_CNT = 0; #define SK_MAX 10 int main(int argc, char *argv[]) { int error,i; socklen_t len; int sk,lstn_sk,clnt_sk[SK_MAX],acpt_sk[SK_MAX],pf_class; int sk1,clnt2_sk; struct sockaddr_in conn_addr,lstn_addr,acpt_addr; struct sockaddr *tmp_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a listen socket*/ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a regular socket*/ for (i = 0 ; i < SK_MAX ; i++) clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); clnt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, SK_MAX-1); /*sctp_connectx () TEST1: Bad socket descriptor, EBADF Expected error*/ len = sizeof(struct sockaddr_in); error = sctp_connectx(-1, (struct sockaddr *) &conn_addr, 1, NULL); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "sctp_connectx with bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() with bad socket descriptor - EBADF"); /*sctp_connectx () TEST2: Invalid socket, ENOTSOCK Expected error*/ error = sctp_connectx(0, (struct sockaddr *) &conn_addr, 1, NULL); if (error != -1 || errno != ENOTSOCK) tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() with invalid socket - ENOTSOCK"); /*sctp_connectx () TEST3: Invalid address, EINVAL Expected error*/ tmp_addr = (struct sockaddr *) malloc(sizeof(struct sockaddr) - 1); tmp_addr->sa_family = AF_INET; error = sctp_connectx(sk, tmp_addr, 1, NULL); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() with invalid address - EINVAL"); /*sctp_connectx () TEST4: Invalid address length, EINVAL Expected error*/ error = sctp_connectx(sk, (struct sockaddr *) &conn_addr, 0, NULL); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address length " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() with invalid address length - EINVAL"); /*sctp_connectx () TEST5: Invalid address family, EINVAL Expect error*/ conn_addr.sin_family = 9090; /*Assigning invalid address family*/ error = sctp_connectx(sk, (struct sockaddr *) &conn_addr, 1, NULL); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address family " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() with invalid address family - EINVAL"); conn_addr.sin_family = AF_INET; /*sctp_connectx () TEST6: Blocking sctp_connectx, should pass*/ /*All the be below blocking sctp_connectx should pass as socket will be listening SK_MAX clients*/ for (i = 0 ; i < SK_MAX ; i++) { error = sctp_connectx(clnt_sk[i], (struct sockaddr *)&conn_addr, 1, NULL); if (error < 0) tst_brkm(TBROK, tst_exit, "valid blocking sctp_connectx " "error:%d, errno:%d", error, errno); } tst_resm(TPASS, "valid blocking sctp_connectx() - SUCCESS"); /*sctp_connectx () TEST7: sctp_connectx when accept queue is full, ECONNREFUSED Expect error*/ /*Now that accept queue is full, the below sctp_connectx should fail*/ error = sctp_connectx(clnt2_sk, (struct sockaddr *) &conn_addr, 1, NULL); if (error != -1 || errno != ECONNREFUSED) tst_brkm(TBROK, tst_exit, "sctp_connectx when accept queue is full " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() when accept queue is full - ECONNREFUSED"); /*Calling a accept first to estblish the pending sctp_connectxions*/ for (i=0 ; i < SK_MAX ; i++) acpt_sk[i] = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len); /*sctp_connectx () TEST8: from a listening socket, EISCONN Expect error*/ error = sctp_connectx(lstn_sk, (struct sockaddr *) &lstn_addr, 1, NULL); if (error != -1 || errno != EISCONN) tst_brkm(TBROK, tst_exit, "sctp_connectx on a listening socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() on a listening socket - EISCONN"); /*sctp_connectx() TEST9: On established socket, EISCONN Expect error*/ i=0; error = sctp_connectx(acpt_sk[i], (struct sockaddr *) &lstn_addr, 1, NULL); if (error != -1 || errno != EISCONN) tst_brkm(TBROK, tst_exit, "sctp_connectx on an established socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() on an established socket - EISCONN"); for (i = 0 ; i < 4 ; i++) { close(clnt_sk[i]); close(acpt_sk[i]); } /* sctp_connectx() TEST10: Re-establish an association that is closed. * should succeed. */ error = sctp_connectx(sk1, (struct sockaddr *)&conn_addr, 1, NULL); if (error < 0) tst_brkm(TBROK, tst_exit, "Re-establish an association that " "is closed error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_connectx() to re-establish a closed association - " "SUCCESS"); close(sk); close(sk1); close(lstn_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_connect.c0000644000175000017500000001745012300634451024650 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the connect () call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: Invalid address * TEST4: Invalid address length * TEST5: Invalid address family * TEST6: Valid blocking connect * TEST7: Connect when accept queue is full * TEST8: On a listening socket * TEST9: On established socket * TEST10: Connect to re-establish a closed association. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include "sctputil.h" char *TCID = __FILE__; int TST_TOTAL = 10; int TST_CNT = 0; #define SK_MAX 10 int main(int argc, char *argv[]) { int error,i; socklen_t len; int sk,lstn_sk,clnt_sk[SK_MAX],acpt_sk[SK_MAX],pf_class; int sk1,clnt2_sk; int fd, err_no = 0; char filename[21]; struct sockaddr_in conn_addr,lstn_addr,acpt_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a listen socket*/ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a regular socket*/ for (i = 0 ; i < SK_MAX ; i++) clnt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); clnt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, SK_MAX-1); /*connect () TEST1: Bad socket descriptor, EBADF Expected error*/ len = sizeof(struct sockaddr_in); error = connect(-1, (const struct sockaddr *) &conn_addr, len); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "connect with bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() with bad socket descriptor - EBADF"); /*connect () TEST2: Invalid socket, ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = connect(fd, (const struct sockaddr *) &conn_addr, len); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "connect with invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "connect() with invalid socket - ENOTSOCK"); /*connect () TEST3: Invalid address, EFAULT Expected error*/ error = connect(sk, (const struct sockaddr *) -1, len); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "connect with invalid address " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() with invalid address - EFAULT"); /*connect () TEST4: Invalid address length, EINVAL Expected error*/ error = connect(sk, (const struct sockaddr *) &conn_addr, (len - 3)); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "connect with invalid address length " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() with invalid address length - EINVAL"); /*connect () TEST5: Invalid address family, EINVAL Expect error*/ conn_addr.sin_family = 9090; /*Assigning invalid address family*/ error = connect(sk, (const struct sockaddr *) &conn_addr, len); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "connect with invalid address family " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() with invalid address family - EINVAL"); conn_addr.sin_family = AF_INET; /*connect () TEST6: Blocking connect, should pass*/ /*All the be below blocking connect should pass as socket will be listening SK_MAX clients*/ for (i = 0 ; i < SK_MAX ; i++) { error = connect(clnt_sk[i], (const struct sockaddr *)&conn_addr, len); if (error < 0) tst_brkm(TBROK, tst_exit, "valid blocking connect " "error:%d, errno:%d", error, errno); } tst_resm(TPASS, "valid blocking connect() - SUCCESS"); /*connect () TEST7: connect when accept queue is full, ECONNREFUSED Expect error*/ /*Now that accept queue is full, the below connect should fail*/ error = connect(clnt2_sk, (const struct sockaddr *) &conn_addr, len); if (error != -1 || errno != ECONNREFUSED) tst_brkm(TBROK, tst_exit, "connect when accept queue is full " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() when accept queue is full - ECONNREFUSED"); /*Calling a accept first to estblish the pending connections*/ for (i=0 ; i < SK_MAX ; i++) acpt_sk[i] = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len); /*connect () TEST8: from a listening socket, EISCONN Expect error*/ error = connect(lstn_sk, (const struct sockaddr *) &lstn_addr, len); if (error != -1 || errno != EISCONN) tst_brkm(TBROK, tst_exit, "connect on a listening socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() on a listening socket - EISCONN"); /*connect() TEST9: On established socket, EISCONN Expect error*/ i=0; error = connect(acpt_sk[i], (const struct sockaddr *) &lstn_addr, len); if (error != -1 || errno != EISCONN) tst_brkm(TBROK, tst_exit, "connect on an established socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() on an established socket - EISCONN"); for (i = 0 ; i < 4 ; i++) { close(clnt_sk[i]); close(acpt_sk[i]); } /* connect() TEST10: Re-establish an association that is closed. * should succeed. */ error = connect(sk1, (const struct sockaddr *)&conn_addr, len); if (error < 0) tst_brkm(TBROK, tst_exit, "Re-establish an association that " "is closed error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect() to re-establish a closed association - " "SUCCESS"); close(sk); close(sk1); close(lstn_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_assoc_shutdown.c0000644000175000017500000001760512300634451025122 0ustar michaelmichael/* 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 * * 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: * Sridhar Samudrala */ /* This is a functional test to verify the graceful shutdown of an * association. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; #define MAX_CLIENTS 10 int main(int argc, char *argv[]) { int svr_sk, clt_sk[MAX_CLIENTS]; sctp_assoc_t svr_associd[MAX_CLIENTS]; sockaddr_storage_t svr_loop, clt_loop[MAX_CLIENTS]; 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; uint32_t ppid; uint32_t stream; struct sctp_assoc_change *sac; char *big_buffer; int i; char *message = "hello, world!\n"; struct sctp_status status; socklen_t status_len; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Create and bind the server socket. */ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); svr_loop.v4.sin_family = AF_INET; svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop)); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(svr_sk); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 1); /* Create and bind all the client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { clt_sk[i] = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); clt_loop[i].v4.sin_family = AF_INET; clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i); test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i])); test_enable_assoc_change(clt_sk[i]); } /* Build up a msghdr structure we can use for all sending. */ outmessage.msg_name = &svr_loop; outmessage.msg_namelen = sizeof(svr_loop); 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; out_iov.iov_base = message; out_iov.iov_len = strlen(message) + 1; /* Send the first message from all the clients to the server. This * will create the associations. */ for (i = 0; i < MAX_CLIENTS; i++) test_sendmsg(clt_sk[i], &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 all client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); } /* Get the communication up message and the data message on the * server sockets for all the clients. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message)+1, MSG_EOR, stream, ppid); sac = (struct sctp_assoc_change *)iov.iov_base; svr_associd[i] = sac->sac_assoc_id; } /* Build up a msghdr structure we can use for all sending. */ outmessage.msg_name = NULL; outmessage.msg_namelen = 0; outmessage.msg_iov = NULL; outmessage.msg_iovlen = 0; 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)); sinfo->sinfo_flags |= SCTP_EOF; /* Shutdown all the associations of the server socket in a loop. */ for (i = 0; i < MAX_CLIENTS; i++) { sinfo->sinfo_assoc_id = svr_associd[i]; /* Verify that the association is present. */ memset(&status, 0, sizeof(struct sctp_status)); status.sstat_assoc_id = sinfo->sinfo_assoc_id; status_len = sizeof(struct sctp_status); error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS, &status, &status_len); if (error) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS): %s", strerror(errno)); /* Call sendmsg() to shutdown the association. */ test_sendmsg(svr_sk, &outmessage, 0, 0); /* Verify that the association is no longer present. */ memset(&status, 0, sizeof(struct sctp_status)); status.sstat_assoc_id = sinfo->sinfo_assoc_id; status_len = sizeof(struct sctp_status); error = getsockopt(svr_sk, SOL_SCTP, SCTP_STATUS, &status, &status_len); if ((error != -1) && (errno != EINVAL)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) " "error:%d errno:%d", error, errno); } close(svr_sk); /* Get the shutdown complete notification. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); close(clt_sk[i]); } tst_resm(TPASS, "Graceful shutdown of associations using SCTP_EOF"); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_tcp_style.c0000644000175000017500000003551012300634451024060 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2003 * Copyright (c) 1999-2001 Motorola, Inc. * * This file is part of the SCTP kernel Implementation * * 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 * * 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: * Sridhar Samudrala */ /* This is a kernel test to verify the TCP-style socket interfaces. */ #include #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 22; int TST_CNT = 0; #define MAX_CLIENTS 10 int main(int argc, char *argv[]) { int clt_sk[MAX_CLIENTS], accept_sk[MAX_CLIENTS]; int listen_sk, clt2_sk, accept2_sk; sockaddr_storage_t clt_loop[MAX_CLIENTS]; sockaddr_storage_t svr_loop, accept_loop, clt2_loop; socklen_t addrlen; int error, i; char *message = "hello, world!\n"; char msgbuf[100]; int pf_class; struct pollfd poll_fd; fd_set set; struct msghdr outmessage; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct iovec out_iov; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sinfo; struct msghdr inmessage; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; char *big_buffer; struct iovec iov; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Initialize the server and client addresses. */ #if TEST_V6 pf_class = PF_INET6; svr_loop.v6.sin6_family = AF_INET6; svr_loop.v6.sin6_addr = in6addr_loopback; svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1); for (i = 0; i < MAX_CLIENTS; i++) { clt_loop[i].v6.sin6_family = AF_INET6; clt_loop[i].v6.sin6_addr = in6addr_loopback; clt_loop[i].v6.sin6_port = htons(SCTP_TESTPORT_2 + i); } clt2_loop.v6.sin6_family = AF_INET6; clt2_loop.v6.sin6_addr = in6addr_loopback; clt2_loop.v6.sin6_port = htons(SCTP_TESTPORT_2 + i); #else pf_class = PF_INET; svr_loop.v4.sin_family = AF_INET; svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); for (i = 0; i < MAX_CLIENTS; i++) { clt_loop[i].v4.sin_family = AF_INET; clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i); } clt2_loop.v4.sin_family = AF_INET; clt2_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt2_loop.v4.sin_port = htons(SCTP_TESTPORT_2 + i); #endif /* Create and bind the listening server socket. */ listen_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_bind(listen_sk, &svr_loop.sa, sizeof(svr_loop)); /* Mark listen_sk as being able to accept new associations. */ test_listen(listen_sk, MAX_CLIENTS-1); /* Create and bind the client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { clt_sk[i] = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i])); } clt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_bind(clt2_sk, &clt2_loop.sa, sizeof(clt2_loop)); addrlen = sizeof(accept_loop); /* Try to do accept on a non-listening socket. It should fail. */ error = accept(clt_sk[0], &accept_loop.sa, &addrlen); if ((-1 != error) && (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "accept on non-listening socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept on non-listening socket"); /* Try to do a connect from a listening socket. It should fail. */ error = connect(listen_sk, (struct sockaddr *)&clt_loop[0], sizeof(clt_loop[0])); if ((-1 != error) && (EISCONN != errno)) tst_brkm(TBROK, tst_exit, "connect to non-listening socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect to non-listening socket"); /* Do a blocking connect from clt_sk's to listen_sk */ for (i = 0; i < MAX_CLIENTS; i++) test_connect(clt_sk[i], &svr_loop.sa, sizeof(svr_loop)); tst_resm(TPASS, "connect to listening socket"); /* Verify that no more connect's can be done after the acceptq * backlog has reached the max value. */ error = connect(clt2_sk, &svr_loop.sa, sizeof(svr_loop)); if ((-1 != error) && (ECONNREFUSED != errno)) tst_brkm(TBROK, tst_exit, "connect after max backlog " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "connect after max backlog"); /* Extract the associations on the listening socket as new sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { poll_fd.fd = listen_sk; poll_fd.events = POLLIN; poll_fd.revents = 0; error = poll(&poll_fd, 1, -1); if ((1 != error) && (1 != poll_fd.revents)) tst_brkm(TBROK, tst_exit, "Unexpected return value " "with poll, error:%d errno:%d, revents:%d", error, errno, poll_fd.revents); addrlen = sizeof(accept_loop); accept_sk[i] = test_accept(listen_sk, &accept_loop.sa, &addrlen); } tst_resm(TPASS, "accept from listening socket"); /* Try to do a connect on an established socket. It should fail. */ error = connect(accept_sk[0], &clt_loop[0].sa, sizeof(clt_loop[0])); if ((-1 != error) || (EISCONN != errno)) tst_brkm(TBROK, tst_exit, "connect on an established socket " "error:%d errno:%d", error, errno); tst_resm(TPASS, "connect on an established socket"); /* Try to do accept on an established socket. It should fail. */ error = accept(accept_sk[0], &accept_loop.sa, &addrlen); if ((-1 != error) && (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "accept on an established socket " "error:%d errno:%d", error, errno); error = accept(clt_sk[0], &accept_loop.sa, &addrlen); if ((-1 != error) && (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "accept on an established socket " "failure: error:%d errno:%d", error, errno); tst_resm(TPASS, "accept on an established socket"); /* Send and receive a message from the client sockets to the accepted * sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { test_send(clt_sk[i], message, strlen(message), 0); test_recv(accept_sk[i], msgbuf, 100, 0); } tst_resm(TPASS, "client sockets -> accepted sockets"); /* Send and receive a message from the accepted sockets to the client * sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { test_send(accept_sk[i], message, strlen(message), 0); test_recv(clt_sk[i], msgbuf, 100, 0); } tst_resm(TPASS, "accepted sockets -> client sockets"); /* Sending a message on a listening socket should fail. */ error = send(listen_sk, message, strlen(message), MSG_NOSIGNAL); if ((-1 != error) || (EPIPE != errno)) tst_brkm(TBROK, tst_exit, "send on a listening socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "send on a listening socket"); /* Trying to receive a message on a listening socket should fail. */ error = recv(listen_sk, msgbuf, 100, 0); if ((-1 != error) || (ENOTCONN != errno)) tst_brkm(TBROK, tst_exit, "recv on a listening socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "recv on a listening socket"); /* TESTCASES for shutdown() */ errno = 0; test_send(accept_sk[0], message, strlen(message), 0); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(clt_sk[0]); /* Do a SHUT_WR on clt_sk[0] to disable any new sends. */ test_shutdown(clt_sk[0], SHUT_WR); /* Reading on a socket that has received SHUTDOWN should return 0 * indicating EOF. */ error = recv(accept_sk[0], msgbuf, 100, 0); if ((0 != error) || (0 != errno)) tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN received socket " "error:%d errno:%d", error, errno); tst_resm(TPASS, "recv on a SHUTDOWN received socket"); /* Read the pending message on clt_sk[0] that was received before * SHUTDOWN call. */ test_recv(clt_sk[0], msgbuf, 100, 0); /* 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; inmessage.msg_controllen = sizeof(incmsg); /* Receive the SHUTDOWN_COMP notification as they are enabled. */ error = test_recvmsg(clt_sk[0], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); tst_resm(TPASS, "recv SHUTDOWN_COMP notification on a SHUT_WR socket"); /* No more messages and the association is SHUTDOWN, should fail. */ error = recv(clt_sk[0], msgbuf, 100, 0); if ((-1 != error) || (ENOTCONN != errno)) tst_brkm(TBROK, tst_exit, "recv on a SHUTDOWN sent socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "recv on a SHUTDOWN sent socket"); errno = 0; /* Do a SHUT_RD on clt_sk[1] to disable any new receives. */ test_shutdown(clt_sk[1], SHUT_RD); error = recv(clt_sk[1], msgbuf, 100, 0); if ((0 != error) || (0 != errno)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket " "error:%d, errno:%d", error, errno); /* Sending a message on SHUT_RD socket. */ test_send(clt_sk[1], message, strlen(message), 0); /* Receive the message sent on SHUT_RD socket. */ test_recv(accept_sk[1], msgbuf, 100, 0); /* Send a message to the SHUT_RD socket. */ test_send(accept_sk[1], message, strlen(message), 0); /* We should not receive the message as the socket is SHUT_RD */ error = recv(clt_sk[1], msgbuf, 100, 0); if ((0 != error) || (0 != errno)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RD socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "recv on a SHUT_RD socket"); /* Do a SHUT_RDWR on clt_sk[2] to disable any new sends/receives. */ test_shutdown(clt_sk[2], SHUT_RDWR); error = recv(accept_sk[2], msgbuf, 100, 0); if ((0 != error) || (0 != errno)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RDWR socket " "error:%d, errno:%d", error, errno); error = recv(clt_sk[2], msgbuf, 100, 0); if ((0 != error) || (0 != errno)) tst_brkm(TBROK, tst_exit, "recv on a SHUT_RDWR socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "recv on a SHUT_RDWR socket"); error = 0; for (i = 0; i < MAX_CLIENTS; i++) close(clt_sk[i]); for (i = 0; i < MAX_CLIENTS; i++) close(accept_sk[i]); /* Test case to verify accept of a CLOSED association. */ /* Do a connect, send and a close to ESTABLISH and CLOSE an * association on the listening socket. */ test_connect(clt2_sk, &svr_loop.sa, sizeof(svr_loop)); test_send(clt2_sk, message, strlen(message), 0); close(clt2_sk); FD_ZERO(&set); FD_SET(listen_sk, &set); error = select(listen_sk + 1, &set, NULL, NULL, NULL); if (1 != error) tst_brkm(TBROK, tst_exit, "select error:%d, " "errno: %d", error, errno); /* Now accept the CLOSED association waiting on the listening * socket. */ accept2_sk = test_accept(listen_sk, &accept_loop.sa, &addrlen); /* Receive the message sent before doing a close. */ test_recv(accept2_sk, msgbuf, 100, 0); /* Receive EOF indication as there are no more messages and the * socket is SHUTDOWN. */ error = recv(accept2_sk, msgbuf, 100, 0); if ((0 != error) || (0 != errno)) tst_brkm(TBROK, tst_exit, "Unexpected error return on " "recv(error:%d, errno:%d)", error, errno); tst_resm(TPASS, "accept of a CLOSED association"); /* Trying to send a message over the CLOSED association should * generate EPIPE. */ error = send(accept2_sk, message, strlen(message), MSG_NOSIGNAL); if ((-1 != error) || (EPIPE != errno)) tst_brkm(TBROK, tst_exit, "send to a CLOSED association " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "send to a CLOSED association"); error = 0; close(accept2_sk); /* Verify that auto-connect can be done on a TCP-style socket using * sendto/sendmsg. */ clt2_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); test_bind(clt2_sk, &clt2_loop.sa, sizeof(clt2_loop)); /* Do a sendto() without a connect() */ test_sendto(clt2_sk, message, strlen(message), 0, &svr_loop.sa, sizeof(svr_loop)); accept2_sk = test_accept(listen_sk, &accept_loop.sa, &addrlen); test_recv(accept2_sk, msgbuf, 100, 0); tst_resm(TPASS, "auto-connect using sendto"); outmessage.msg_name = &svr_loop; outmessage.msg_namelen = sizeof(svr_loop); outmessage.msg_iov = NULL; outmessage.msg_iovlen = 0; 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)); /* Verify that SCTP_EOF cannot be used to shutdown an association * on a TCP-style socket. */ sinfo->sinfo_flags |= SCTP_EOF; error = sendmsg(clt2_sk, &outmessage, 0); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_EOF flag " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sendmsg with SCTP_EOF flag"); /* Verify that SCTP_ABORT cannot be used to abort an association * on a TCP-style socket. */ sinfo->sinfo_flags |= SCTP_ABORT; error = sendmsg(clt2_sk, &outmessage, 0); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_ABORT flag " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sendmsg with SCTP_ABORT flag"); /* Verify that a normal message can be sent using sendmsg. */ outmessage.msg_iov = &out_iov; outmessage.msg_iovlen = 1; out_iov.iov_base = message; out_iov.iov_len = strlen(message) + 1; sinfo->sinfo_flags = 0; test_sendmsg(clt2_sk, &outmessage, 0, strlen(message)+1); test_recv(accept2_sk, msgbuf, 100, 0); tst_resm(TPASS, "sendmsg with no flags"); close(clt2_sk); close(accept2_sk); close(listen_sk); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_threads.c0000644000175000017500000001311312300634451024641 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file does send and receive for 500 threads on a unique association for * THREAD_SND_RCV_LOOPS = 10 many times. To change the number of threads * change the THREADS valuen and loop change the THREAD_SND_RCV_LOOPS. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include #define THREADS 10 /* FIXME should be 500 instead of 10 */ #define THREAD_SND_RCV_LOOPS 10 char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; int client_sk; int server_sk; int acpt_sk; struct sockaddr_in conn_addr; char *message = "hello, world!\n"; void t_recv(void) { int cnt; struct msghdr inmessage; struct iovec iov; char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; char * buffer; memset(&inmessage, 0, sizeof(inmessage)); buffer = malloc(100); iov.iov_base = buffer; iov.iov_len = 100; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); cnt = test_recvmsg(acpt_sk,&inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, cnt, strlen(message) + 1, MSG_EOR, 0, 0); } void t_send(void) { struct msghdr outmessage; struct sctp_sndrcvinfo *sinfo; struct cmsghdr *cmsg; struct iovec out_iov; char outcmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &conn_addr; outmessage.msg_namelen = sizeof(conn_addr); 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)); outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = (strlen(message) + 1); test_sendmsg(client_sk, &outmessage, 0, strlen(message)+1); } void *relay(void *arg) { int id = *(int *) arg; if (id == 0) { t_send(); } else { t_recv(); t_send(); } pthread_exit(NULL); } int main(void) { int cnt,i; int pth[THREADS]; pthread_t thread[THREADS]; int status; int exit_status; void * result; pthread_attr_t attr; struct sockaddr_in lstn_addr; socklen_t len = sizeof(struct sockaddr_in); struct sockaddr_in svr_addr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); server_sk = test_socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); client_sk = test_socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); test_bind(server_sk, (struct sockaddr *)&lstn_addr, sizeof(struct sockaddr_in)); test_listen(server_sk,10); test_connect(client_sk,(struct sockaddr *)&conn_addr,len); acpt_sk = test_accept(server_sk, (struct sockaddr *)&svr_addr, &len); for ( i = 0; i < THREAD_SND_RCV_LOOPS; i++ ) { for (cnt = 0; cnt < THREADS; cnt++) { pth[cnt] = cnt; status = pthread_create(&thread[cnt], &attr, relay, &pth[cnt]); if (status) tst_brkm(TBROK, tst_exit, "pthread_create " "failed status:%d, errno:%d", status, errno); } pthread_attr_destroy(&attr); for (cnt = 0; cnt < THREADS ; cnt++) { exit_status = pthread_join (thread[cnt], &result); if (exit_status == -1) tst_brkm(TBROK, tst_exit, "pthread_join " "Thread #%d exited with status:%d", cnt, exit_status); } } tst_resm(TPASS, "send and receive data across multiple threads - " "SUCCESS"); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_sctp_sendrecvmsg.c0000644000175000017500000002661312300634451025427 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2003 * Copyright (c) 2003 Intel Corp. * * 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 * * 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: * To compile the v6 version, set the symbol TEST_V6 to 1. * * Written or modified by: * Ardelle Fan * Sridhar Samudrala */ /* This is a basic functional test for the SCTP new library APIs * sctp_sendmsg() and sctp_recvmsg(). test_timetolive.c is rewritten using * these new APIs. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 10; int TST_CNT = 0; /* RCVBUF value, and indirectly RWND*2 */ #define SMALL_RCVBUF 3000 #define SMALL_MAXSEG 100 /* This is extra data length to ensure rwnd closes */ #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; sockaddr_storage_t msgname; int error; int pf_class; uint32_t ppid; uint32_t stream; struct sctp_event_subscribe subscribe; char *big_buffer; int offset, msg_flags; socklen_t msgname_len; size_t buflen; struct sctp_send_failed *ssf; struct sctp_sndrcvinfo sinfo; struct sctp_sndrcvinfo snd_sinfo; sctp_assoc_t associd1; socklen_t len, oldlen; 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; 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; 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); /* 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)); /* * Set the RWND small so we can fill it up easily. */ len = sizeof(int); error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &oldlen, &len); if (error) tst_brkm(TBROK, tst_exit, "can't get rcvbuf size: %s", strerror(errno)); len = SMALL_RCVBUF; /* Really becomes 2xlen when set. */ 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. */ ppid = rand(); stream = 1; test_sctp_sendmsg(sk1, message, strlen(message) + 1, (struct sockaddr *)&loop2, sizeof(loop2), ppid, 0, stream, 0, 0); tst_resm(TPASS, "sctp_sendmsg"); /* Get the communication up message on sk2. */ buflen = REALLY_BIG; big_buffer = test_malloc(buflen); msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk2, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); #if 0 associd2 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id; #endif test_check_buf_notification(big_buffer, error, msg_flags, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); /* Get the communication up message on sk1. */ buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk1, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); associd1 = ((struct sctp_assoc_change *)big_buffer)->sac_assoc_id; test_check_buf_notification(big_buffer, error, msg_flags, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); tst_resm(TPASS, "sctp_recvmsg SCTP_COMM_UP notification"); /* Get the first message which was sent. */ buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk2, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); test_check_buf_data(big_buffer, error, msg_flags, &sinfo, strlen(message) + 1, MSG_EOR, stream, ppid); tst_resm(TPASS, "sctp_recvmsg data"); /* 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 a fillmsg of size %d", gstatus.sstat_rwnd+RWND_SLOP); fillmsg = malloc(gstatus.sstat_rwnd+RWND_SLOP); /* Send a fillmsg */ memset(fillmsg, 'X', gstatus.sstat_rwnd+RWND_SLOP); fillmsg[gstatus.sstat_rwnd+RWND_SLOP-1] = '\0'; ppid++; stream++; test_sctp_sendmsg(sk1, fillmsg, gstatus.sstat_rwnd+RWND_SLOP, (struct sockaddr *)&loop2, sizeof(loop2), ppid, 0, stream, 0, 0); /* 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); tst_resm(TPASS, "sctp_sendmsg with ttl"); /* Next send a message that won't time out. */ test_sctp_sendmsg(sk1, nottlmsg, strlen(nottlmsg) + 1, (struct sockaddr *)&loop2, sizeof(loop2), ppid, 0, stream, 0, 0); tst_resm(TPASS, "sctp_sendmsg with zero ttl"); /* And finally a fragmented message that will time out. */ memset(ttlfrag, '0', sizeof(ttlfrag)); ttlfrag[sizeof(ttlfrag)-1] = '\0'; test_sctp_sendmsg(sk1, ttlfrag, sizeof(ttlfrag), (struct sockaddr *)&loop2, sizeof(loop2), ppid, 0, stream, 2000, 0); tst_resm(TPASS, "sctp_sendmsg fragmented msg with ttl"); /* Sleep waiting for the message to time out. */ tst_resm(TINFO, "** SLEEPING for 3 seconds **"); sleep(3); /* Get the fillmsg. */ do { buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; test_sctp_recvmsg(sk2, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); } while (!(msg_flags & MSG_EOR)); /* Get the message that did NOT time out. */ buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk2, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); test_check_buf_data(big_buffer, error, msg_flags, &sinfo, strlen(nottlmsg) + 1, MSG_EOR, stream, ppid); if (0 != strncmp(big_buffer, nottlmsg, strlen(nottlmsg))) tst_brkm(TBROK, tst_exit, "sctp_recvmsg: Wrong Message !!!"); tst_resm(TPASS, "sctp_recvmsg msg with zero ttl"); /* Get the SEND_FAILED notification for the message that DID * time out. */ buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk1, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); test_check_buf_notification(big_buffer, error, msg_flags, sizeof(struct sctp_send_failed) + strlen(ttlmsg) + 1, SCTP_SEND_FAILED, 0); ssf = (struct sctp_send_failed *)big_buffer; if (0 != strncmp(ttlmsg, (char *)ssf->ssf_data, strlen(ttlmsg) + 1)) tst_brkm(TBROK, tst_exit, "SEND_FAILED data mismatch"); tst_resm(TPASS, "sctp_recvmsg SEND_FAILED for message with ttl"); offset = 0; /* Get the SEND_FAILED notifications for the fragmented message that * timed out. */ do { buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk1, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); test_check_buf_notification(big_buffer, error, msg_flags, sizeof(struct sctp_send_failed) + SMALL_MAXSEG, SCTP_SEND_FAILED, 0); ssf = (struct sctp_send_failed *)big_buffer; 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, "sctp_recvmsg SEND_FAILED for fragmented message with " "ttl"); snd_sinfo.sinfo_ppid = rand(); snd_sinfo.sinfo_flags = 0; snd_sinfo.sinfo_stream = 2; snd_sinfo.sinfo_timetolive = 0; snd_sinfo.sinfo_assoc_id = associd1; test_sctp_send(sk1, message, strlen(message) + 1, &snd_sinfo, MSG_NOSIGNAL); buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk2, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); test_check_buf_data(big_buffer, error, msg_flags, &sinfo, strlen(message) + 1, MSG_EOR, snd_sinfo.sinfo_stream, snd_sinfo.sinfo_ppid); tst_resm(TPASS, "sctp_send"); /* Shut down the link. */ close(sk1); /* Get the shutdown complete notification. */ buflen = REALLY_BIG; msgname_len = sizeof(msgname); msg_flags = 0; error = test_sctp_recvmsg(sk2, big_buffer, buflen, (struct sockaddr *)&msgname, &msgname_len, &sinfo, &msg_flags); test_check_buf_notification(big_buffer, error, msg_flags, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); close(sk2); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_peeloff.c0000644000175000017500000002303412300634451023470 0ustar michaelmichael/* 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 * * 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: * Sridhar Samudrala */ /* This is a Functional test to verify the new SCTP interface sctp_peeloff() * that can be used to branch off an association into a separate socket. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 6; int TST_CNT = 0; #define MAX_CLIENTS 10 int main(int argc, char *argv[]) { int svr_sk, clt_sk[MAX_CLIENTS], peeloff_sk[MAX_CLIENTS]; sctp_assoc_t svr_associd[MAX_CLIENTS]; sockaddr_storage_t svr_loop, clt_loop[MAX_CLIENTS]; 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; uint32_t ppid; uint32_t stream; struct sctp_assoc_change *sac; char *big_buffer; int i; char *message = "hello, world!\n"; int pf_class; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); #if TEST_V6 pf_class = PF_INET6; svr_loop.v6.sin6_family = AF_INET6; svr_loop.v6.sin6_addr = in6addr_loopback; svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1); #else pf_class = PF_INET; svr_loop.v4.sin_family = AF_INET; svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); #endif /* Create and bind the server socket. */ svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(svr_sk, &svr_loop.sa, sizeof(svr_loop)); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(svr_sk); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 1); /* Create and bind all the client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { clt_sk[i] = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); #if TEST_V6 clt_loop[i].v6.sin6_family = AF_INET6; clt_loop[i].v6.sin6_addr = in6addr_loopback; clt_loop[i].v6.sin6_port = htons(SCTP_TESTPORT_2 + i); #else clt_loop[i].v4.sin_family = AF_INET; clt_loop[i].v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop[i].v4.sin_port = htons(SCTP_TESTPORT_2 + i); #endif test_bind(clt_sk[i], &clt_loop[i].sa, sizeof(clt_loop[i])); test_enable_assoc_change(clt_sk[i]); } /* Send the first message from all the clients to the server. This * will create the associations. */ outmessage.msg_name = &svr_loop; outmessage.msg_namelen = sizeof(svr_loop); 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; for (i = 0; i < MAX_CLIENTS; i++) test_sendmsg(clt_sk[i], &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 all client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; clt_associd[i] = sac->sac_assoc_id; #endif } /* Get the communication up message and the data message on the * server sockets for all the clients. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &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; svr_associd[i] = sac->sac_assoc_id; inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); } /* Branch off all the associations on the server socket to separate * individual sockets. */ for (i = 0; i < MAX_CLIENTS; i++) peeloff_sk[i] = test_sctp_peeloff(svr_sk, svr_associd[i]); tst_resm(TPASS, "sctp_peeloff"); errno = 0; /* Verify that a peeled off socket is not allowed to do a listen(). */ error = listen(peeloff_sk[0], 1); if (error != -1) tst_brkm(TBROK, tst_exit, "listen on a peeled off socket " "error: %d, errno: %d", error, errno); tst_resm(TPASS, "listen on a peeled off socket"); errno = 0; /* Verify that an association cannot be branched off an already * peeled-off socket. */ if ((-1 != sctp_peeloff(peeloff_sk[0], svr_associd[0])) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "sctp_peeloff on a peeled off " "socket error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_peeloff on a peeled off socket"); /* Send a message from all the client sockets to the server socket. */ for (i = 0; i < MAX_CLIENTS; i++) test_sendmsg(clt_sk[i], &outmessage, 0, strlen(message)+1); /* Receive the sent messages on the peeled off server sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(peeloff_sk[i], &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); } tst_resm(TPASS, "Receive msgs on peeled off sockets"); /* Send a message from all the peeled off server sockets to the client * sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { outmessage.msg_name = &clt_loop[i]; outmessage.msg_namelen = sizeof(clt_loop[i]); test_sendmsg(peeloff_sk[i], &outmessage, 0, strlen(message)+1); } /* Receive the messages sent from the peeled of server sockets on * the client sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); } tst_resm(TPASS, "Send msgs on peeled off sockets"); errno = 0; /* Verify that a peeled-off socket cannot initialize a new * association by trying to send a message to a client that is not * associated with the peeled-off socket. * The message is sent to the client that is associated with the * socket. */ outmessage.msg_name = &clt_loop[1]; outmessage.msg_namelen = sizeof(clt_loop[1]); test_sendmsg(peeloff_sk[0], &outmessage, 0, strlen(message)+1); inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[0], &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); tst_resm(TPASS, "peeled off socket cannot initialize a new assoc"); close(svr_sk); /* Close all the peeled off server sockets. */ for (i = 0; i < MAX_CLIENTS; i++) close(peeloff_sk[i]); /* Get the shutdown complete notification from all the client * sockets. */ for (i = 0; i < MAX_CLIENTS; i++) { inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk[i], &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); close(clt_sk[i]); } /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_socket_bind_listen.c0000644000175000017500000002265312300634451027062 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the socket (), bind () and listen () for * 1-1 style sockets * * socket () Tests: * --------------- * TEST1: Invalid domain * TEST2: Invalid type * TEST3: Opening a TCP style socket * * bind () Tests: * ------------- * TEST4: Invalid address * TEST5: Invalid address length * TEST6: Invalid socket descriptor * TEST7: Invalid host name * TEST8: On a socket that is already bound * TEST9: On reserved ports * TEST10: INADDR_ANY address and non-zero port * TEST11: INADDR_ANY address and zero port * TEST12: Local address and zero port * * listen () Tests: * --------------- * TEST13: Bad socket descriptor * TEST14: Invalid socket * TEST15: Listening a bound socket * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #define SCTP_RESERVED_PORT 7 #define SCTP_INV_LOOPBACK "172.31.43.112" char *TCID = __FILE__; int TST_TOTAL = 15; int TST_CNT = 0; int main(int argc, char *argv[]) { int sk,pf_class; int error = 0; int uid; int fd, err_no = 0; char filename[21]; struct sockaddr_in bind_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; /* socket() TEST1: Invalid domain, EAFNOSUPPORT Expected error */ sk = socket(-1, SOCK_STREAM, IPPROTO_SCTP); if (sk != -1 || errno != EAFNOSUPPORT) tst_brkm(TBROK, tst_exit, "socket() with invalid domain " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "socket() with invalid domain - EAFNOSUPPORT"); /*socket() TEST2 : Invalid type, EINVAL Expected error*/ sk = socket(pf_class, -1, IPPROTO_SCTP); if (sk != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "socket() with invalid type " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "socket() with invalid type - EINVAL"); /*socket() TEST3: opening a socket*/ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); if (sk < 0) tst_brkm(TBROK, tst_exit, "valid socket() call " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "socket() - SUCCESS"); /*bind() TEST4: Invalid structure, EFAULT Expected error */ error = bind(sk, (struct sockaddr *)-1, sizeof(struct sockaddr_in)); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "bind() with invalid address ptr " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() with invalid address ptr - EFAULT"); /*bind() TEST5: Invalid address length, EINVAL Expect error*/ bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; bind_addr.sin_port = htons(SCTP_TESTPORT_1); error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr)-2); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "bind() with invalid address length " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() with invalid address length - EINVAL"); /*bind() TEST6: Invalid socket descriptor, ENOTSOCK Expect Error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = bind(fd, (struct sockaddr *) &bind_addr, sizeof(bind_addr)); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "bind() with invalid socket " "descriptor error:%d, errno:%d", error, err_no); tst_resm(TPASS, "bind() with invalid socket descriptor - ENOTSOCK"); /*bind() TEST7: Invalid host name, EADDRNOTAVAIL Expect Error*/ /*Assigning invalid host name*/ bind_addr.sin_addr.s_addr = inet_addr(SCTP_INV_LOOPBACK); error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr)); if (error != -1 || errno != EADDRNOTAVAIL) tst_brkm(TBROK, tst_exit, "bind() with invalid local " "address error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() with invalid local address - EADDRNOTAVAIL"); /*bind() TEST8: Bind on a socket that has already called bind EINAVL, Expected error*/ bind_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; /*Calling bind first time, it should pass*/ test_bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr)); error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr)); if (error != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "bind() on an already bound socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() on an already bound socket - EINVAL"); /*Closing the socket which succeed in bind() */ close(sk); /*Opening the socket again for further test*/ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*bind() TEST9: Bind on reserved ports EACCES, Expected error*/ /*Assigning a reserved port*/ uid = getuid(); if (uid != 0) { bind_addr.sin_port = htons(SCTP_RESERVED_PORT); error = bind(sk, (struct sockaddr *) &bind_addr, sizeof(bind_addr)); if (error != -1 || errno != EACCES) tst_brkm(TBROK, tst_exit, "bind() on reserverd port " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() on reserved port - EACCESS"); } /*bind() TEST10: INADDR_ANY address and non-zero port, bind() should succeed*/ bind_addr.sin_addr.s_addr = INADDR_ANY; bind_addr.sin_port = htons(SCTP_TESTPORT_1); error = bind(sk, (struct sockaddr *) &bind_addr,sizeof(bind_addr)); if ( error < 0 ) tst_brkm(TBROK, tst_exit, "bind() with INADDR_ANY address and " "non-zero port error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() with INADDR_ANY address and non-zero port - " "SUCCESS"); /*Closing the socket which succeed in bind() */ close(sk); /*Opening the socket again for further test*/ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*bind() TEST11: INADDR_ANY address and zero port, bind() should succeed*/ bind_addr.sin_port = 0; error = bind(sk, (struct sockaddr *) &bind_addr,sizeof(bind_addr)); if ( error < 0 ) tst_brkm(TBROK, tst_exit, "bind() with INADDR_ANY address and " "zero port error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() with INADDR_ANY address and zero port - " "SUCCESS"); /*Closing the socket which succeed in bind() */ close(sk); /*Opening the socket again for further test*/ sk = socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*bind() TEST12: local address and zero port, bind() should succeed*/ bind_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; bind_addr.sin_port = 0; error = bind(sk, (struct sockaddr *) &bind_addr,sizeof(bind_addr)); if ( error < 0 ) tst_brkm(TBROK, tst_exit, "bind() with local address and " "zero port error:%d, errno:%d", error, errno); tst_resm(TPASS, "bind() with local address and zero port - " "SUCCESS"); /*listen() TEST13: Bad socket descriptor EBADF, Expected error*/ error = listen(-1, 3); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "listen() with bad socket descriptor " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "listen() with bad socket descriptor - EBADF"); /*listen() TEST14: Invalid socket ENOTSOCK, Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = listen(fd, 3); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "listen() with invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "listen() with invalid socket - ENOTSOCK"); /*listen() TEST15:listen on a bound socket, should succeed*/ error = listen(sk, 3); if ( error < 0 ) tst_brkm(TBROK, tst_exit, "listen() on a bound socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "listen() on a bound socket - SUCCESS"); close(sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_sockopt.c0000644000175000017500000003745012300634451024703 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test negative scenarios for getsockopt () * setsockopt () call for 1-1 style sockets * * setsockopt () Tests: * ------------------- * TEST1: setsockopt: Bad socket descriptor * TEST2: setsockopt: Invalid socket * TEST3: setsockopt: Invalid level * TEST4: setsockopt: Invalid option buffer * TEST5: setsockopt: Invalid option name * TEST6: getsockopt: Bad socket descriptor * TEST7: getsockopt: Invalid socket * TEST8: getsockopt: Invalid option buffer * TEST9: getsockopt: Invalid option name * * TEST10: getsockopt: SCTP_INITMSG * TEST11: setsockopt: SCTP_INITMSG * TEST12: setsockopt: SO_LINGER * TEST13: getsockopt: SO_LINGER * TEST14: getsockopt: SO_RCVBUF * TEST15: getsockopt: SCTP_STATUS * TEST16: setsockopt: SO_RCVBUF * TEST17: setsockopt: SO_SNDBUF * TEST18: getsockopt: SO_SNDBUF * TEST19: getsockopt: SCTP_PRIMARY_ADDR * TEST20: setsockopt: SCTP_PRIMARY_ADDR * TEST21: getsockopt: SCTP_ASSOCINFO * TEST22: setsockopt: SCTP_ASSOCINFO * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * */ #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 22; int TST_CNT = 0; int main(void) { int error; socklen_t len; int sk, sk1, sk2, acpt_sk, pf_class; struct sctp_rtoinfo grtinfo; struct sockaddr_in lstn_addr, conn_addr; struct sctp_initmsg ginmsg; /*get the value for SCTP_INITMSG*/ struct sctp_initmsg sinmsg; /*set the value for SCTP_INITMSG*/ struct linger slinger; /*SO_LINGER structure*/ struct linger glinger; /*SO_LINGER structure*/ struct sockaddr_in addr; struct sockaddr_in *gaddr; struct sctp_status gstatus; /*SCTP_STATUS option*/ int rcvbuf_val_get, rcvbuf_val_set; /*get and set var for SO_RCVBUF*/ int sndbuf_val_get, sndbuf_val_set;/*get and set var for SO_SNDBUF*/ struct sctp_prim gprimaddr;/*SCTP_PRIMARY_ADDR get*/ struct sctp_prim sprimaddr;/*SCTP_PRIMARY_ADDR set*/ struct sctp_assocparams sassocparams; /* SCTP_ASSOCPARAMS set */ struct sctp_assocparams gassocparams; /* SCTP_ASSOCPARAMS get */ int fd, err_no = 0; char filename[21]; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*setsockopt() TEST1: Bad socket descriptor EBADF, Expected error*/ error = setsockopt(-1, IPPROTO_SCTP, 0, 0, 0); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "setsockopt with a bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() with a bad socket descriptor - EBADF"); /*setsockopt() TEST2: Invalid socket ENOTSOCK, Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = setsockopt(fd, IPPROTO_SCTP, 0, 0, 0); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "setsockopt with an invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "setsockopt() with an invalid socket - ENOTSOCK"); /*setsockopt() TEST3: Invalid level ENOPROTOOPT, Expected error*/ error = setsockopt(sk, -1, SCTP_RTOINFO, 0, 0); if (error != -1 || errno != ENOPROTOOPT) tst_brkm(TBROK, tst_exit, "setsockopt with invalid level " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() with an invalid level - ENOPROTOOPT"); /*setsockopt() TEST4: Invalid option buffer EFAULT, Expected error*/ error = setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, (const struct sctp_rtoinfo *)-1, sizeof(struct sctp_rtoinfo)); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "setsockopt with invalid option " "buffer error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() with invalid option buffer - EFAULT"); /*setsockopt() TEST5: Invalid option Name EOPNOTSUPP, Expected error*/ error = setsockopt(sk, IPPROTO_SCTP, SCTP_AUTOCLOSE, 0, 0); if (error != -1 || errno != EOPNOTSUPP) tst_brkm(TBROK, tst_exit, "setsockopt with invalid option " "name error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() with invalid option name - EOPNOTSUPP"); /*getsockopt() TEST6: Bad socket descriptor EBADF, Expected error*/ error = getsockopt(-1, IPPROTO_SCTP, 0, 0, 0); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "getsockopt with a bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() with a bad socket descriptor - EBADF"); /*getsockopt() TEST7: Invalid socket ENOTSOCK, Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = getsockopt(fd, IPPROTO_SCTP, 0, 0, 0); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "getsockopt with an invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "getsockopt() with an invalid socket - ENOTSOCK"); #if 0 /*getsockopt() TEST3: Invalid level ENOPROTOOPT, Expected error*/ /*I have commented this test case because it is returning EOPNOTSUPP. When I checked the code there also it is returning EOPNOTSUPP. As this is not specific to TCP style, I do not want to do the code change*/ error = getsockopt(sk, -1, SCTP_RTOINFO, 0, 0); if (error != -1 || errno != ENOPROTOOPT) tst_brkm(TBROK, tst_exit, "getsockopt with invalid level " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() with an invalid level - ENOPROTOOPT"); #endif len = sizeof(struct sctp_rtoinfo); /*getsockopt() TEST8: Invalid option buffer EFAULT, Expected error*/ error = getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, (struct sctp_rtoinfo *)-1, &len); if (error != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "getsockopt with invalid option " "buffer error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() with invalid option buffer - EFAULT"); /*getsockopt() TEST9: Invalid option Name EOPNOTSUPP, Expected error*/ error = getsockopt(sk, IPPROTO_SCTP, SCTP_AUTOCLOSE, &grtinfo, &len); if (error != -1 || errno != EOPNOTSUPP) tst_brkm(TBROK, tst_exit, "getsockopt with invalid option " "name error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() with invalid option name - EOPNOTSUPP"); close(sk); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); sk2 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); len = sizeof(struct sctp_initmsg); /* TEST10: Test cases for getsockopt SCTP_INITMSG */ test_getsockopt(sk1, SCTP_INITMSG, &ginmsg, &len); tst_resm(TPASS, "getsockopt() SCTP_INITMSG - SUCCESS"); sinmsg.sinit_num_ostreams = 5; sinmsg.sinit_max_instreams = 5; sinmsg.sinit_max_attempts = 3; sinmsg.sinit_max_init_timeo = 30; /* TEST11: Test case for setsockopt SCTP_INITMSG */ test_setsockopt(sk1, SCTP_INITMSG, &sinmsg, sizeof(sinmsg)); test_getsockopt(sk1, SCTP_INITMSG, &ginmsg, &len); if (sinmsg.sinit_num_ostreams != ginmsg.sinit_num_ostreams && sinmsg.sinit_max_instreams != ginmsg.sinit_max_instreams && sinmsg.sinit_max_attempts != ginmsg.sinit_max_attempts && sinmsg.sinit_max_init_timeo != ginmsg.sinit_max_init_timeo) tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_INITMSG " "compare failed"); tst_resm(TPASS, "setsockopt() SCTP_INITMSG - SUCCESS"); /*Now get the values on different endpoint*/ test_getsockopt(sk2, SCTP_INITMSG, &ginmsg, &len); /*Comparison should not succeed here*/ if (sinmsg.sinit_num_ostreams == ginmsg.sinit_num_ostreams && sinmsg.sinit_max_instreams == ginmsg.sinit_max_instreams && sinmsg.sinit_max_attempts == ginmsg.sinit_max_attempts && sinmsg.sinit_max_init_timeo == ginmsg.sinit_max_init_timeo) tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_INITMSG " "unexpected compare success"); /* SO_LINGER Test with l_onff = 0 and l_linger = 0 */ slinger.l_onoff = 0; slinger.l_linger = 0; test_bind(sk1, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); test_listen(sk1, 10 ); len = sizeof(struct sockaddr_in); test_connect(sk2, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(sk1, (struct sockaddr *)&addr, &len); len = sizeof(struct linger); /* TEST12: Test case for setsockopt SO_LINGER */ error = setsockopt(sk2, SOL_SOCKET, SO_LINGER, &slinger, len); if (error < 0) tst_brkm(TBROK, tst_exit, "setsockopt SO_LINGER " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() SO_LINGER - SUCCESS"); /* TEST13: Test case for getsockopt SO_LINGER */ error = getsockopt(sk2, SOL_SOCKET, SO_LINGER, &glinger, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SO_LINGER " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() SO_LINGER - SUCCESS"); if (slinger.l_onoff != glinger.l_onoff || slinger.l_linger != glinger.l_linger) tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SO_LINGER " "compare failed"); /*First gets the default SO_RCVBUF value and comapres with the value obtained from SCTP_STATUS*/ len = sizeof(int); /* TEST14: Test case for getsockopt SO_RCVBUF */ error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_get, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SO_RCVBUF " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() SO_RCVBUF - SUCCESS"); len = sizeof(struct sctp_status); /* TEST15: Test case for getsockopt SCTP_STATUS */ error = getsockopt(sk2, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_STATUS " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() SCTP_STATUS - SUCCESS"); /* Reducing the SO_RCVBUF value using setsockopt() */ /* Upstream has changed the MIN_RCVBUF (2048 + sizeof(struct sk_buff)) */ len = sizeof(int); rcvbuf_val_set = 2048; /* TEST16: Test case for setsockopt SO_RCVBUF */ error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_set, len); if (error < 0) tst_brkm(TBROK, tst_exit, "setsockopt SO_RCVBUF " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() SO_RCVBUF - SUCCESS"); error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_get, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SO_RCVBUF " "error:%d, errno:%d", error, errno); if ((2 * rcvbuf_val_set) != rcvbuf_val_get) tst_brkm(TBROK, tst_exit, "Comparison failed:Set value and " "got value differs Set Value=%d Get Value=%d", (2*rcvbuf_val_set), rcvbuf_val_get); sndbuf_val_set = 2304; /* TEST17: Test case for setsockopt SO_SNDBUF */ error = setsockopt(sk2, SOL_SOCKET, SO_SNDBUF, &sndbuf_val_set, len); if (error < 0) tst_brkm(TBROK, tst_exit, "setsockopt SO_SNDBUF " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() SO_SNDBUF - SUCCESS"); /* TEST18: Test case for getsockopt SO_SNDBUF */ error = getsockopt(sk2, SOL_SOCKET, SO_SNDBUF, &sndbuf_val_get, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SO_SNDBUF " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() SO_SNDBUF - SUCCESS"); if ((2 * sndbuf_val_set) != sndbuf_val_get) tst_brkm(TBROK, tst_exit, "Comparison failed:Set value and " "got value differs Set Value=%d Get Value=%d\n", (2*sndbuf_val_set), sndbuf_val_get); /* Getting the primary address using SCTP_PRIMARY_ADDR */ len = sizeof(struct sctp_prim); /* TEST19: Test case for getsockopt SCTP_PRIMARY_ADDR */ error = getsockopt(sk2,IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &gprimaddr, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_PRIMARY_ADDR " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() SCTP_PRIMARY_ADDR - SUCCESS"); gaddr = (struct sockaddr_in *) &gprimaddr.ssp_addr; if(htons(gaddr->sin_port) != lstn_addr.sin_port && gaddr->sin_family != lstn_addr.sin_family && gaddr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_PRIMARY_ADDR value " "mismatch"); memcpy(&sprimaddr, &gprimaddr, sizeof(struct sctp_prim)); /* TEST20: Test case for setsockopt SCTP_PRIMARY_ADDR */ error = setsockopt(sk2,IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &sprimaddr, len); if (error < 0) tst_brkm(TBROK, tst_exit, "setsockopt SCTP_PRIMARY_ADDR " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt() SCTP_PRIMARY_ADDR - SUCCESS"); /* TEST21: Test case for getsockopt SCTP_PRIMARY_ADDR */ /* Getting the association info using SCTP_ASSOCINFO */ len = sizeof(struct sctp_assocparams); error = getsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &gassocparams, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "getsockopt() SCTP_ASSOCINFO - SUCCESS"); /* TEST21: Test case for setsockopt SCTP_ASSOCINFO */ memcpy(&sassocparams, &gassocparams, sizeof(struct sctp_assocparams)); sassocparams.sasoc_asocmaxrxt += 5; sassocparams.sasoc_cookie_life += 10; error = setsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &sassocparams, len); if (error < 0) tst_brkm(TBROK, tst_exit, "setsockopt SCTP_ASSOCINFO " "error:%d, errno:%d", error, errno); error = getsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &gassocparams, &len); if (error < 0) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO " "error:%d, errno:%d", error, errno); if (sassocparams.sasoc_asocmaxrxt != gassocparams.sasoc_asocmaxrxt || sassocparams.sasoc_cookie_life != gassocparams.sasoc_cookie_life) tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO value " "mismatch"); tst_resm(TPASS, "setsockopt() SCTP_ASSOCINFO - SUCCESS"); close(sk2); close(sk1); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_initmsg_connect.c0000644000175000017500000000677012300634451026405 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * When init timeout is set to zero, a connect () crashed the system. This case * tests the fix for the same. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 1; int TST_CNT = 0; int main (int argc, char **argv) { int sk1, sk2, sk3, pf_class; socklen_t len; struct sockaddr_in lstn_addr, acpt_addr; struct sockaddr_in conn_addr; char * buffer_rcv; struct sctp_initmsg sinmsg; char *message = "Hello World!\n"; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); /* Opening the socket*/ pf_class = PF_INET; sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); sk3 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); test_bind(sk3, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); len = sizeof(struct sctp_initmsg); sinmsg.sinit_num_ostreams = 65535; sinmsg.sinit_max_instreams = 10; sinmsg.sinit_max_attempts = 1; sinmsg.sinit_max_init_timeo = 0; test_setsockopt(sk1, SCTP_INITMSG, &sinmsg, len); sinmsg.sinit_num_ostreams = 10; sinmsg.sinit_max_instreams = 65535; test_setsockopt(sk3, SCTP_INITMSG, &sinmsg, len); test_listen(sk3, 1); len = sizeof(struct sockaddr_in); test_connect(sk1, (struct sockaddr *) &conn_addr, len); sk2 = test_accept(sk3, (struct sockaddr *) &acpt_addr, &len); test_sctp_sendmsg(sk1, message, strlen(message) + 1, (struct sockaddr *)&conn_addr, len, 0, 0, 65534, 0, 0); buffer_rcv = malloc(100); test_recv(sk2, buffer_rcv, (strlen(message) + 1), MSG_NOSIGNAL); tst_resm(TPASS, "connect() with init timeout set to 0 - SUCCESS"); close (sk1); close (sk2); close (sk3); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_sockopt.c0000644000175000017500000012410012300634451023526 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2001, 2004 * 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 * * 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: * La Monte H.P. Yarroll * Karl Knutson * Hui Huang * Jon Grimm * Sridhar Samudrala */ /* This is a functional test to verify the various SCTP level socket * options that can be used to get information about existing SCTP * associations and to configure certain parameters. */ #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 29; int TST_CNT = 0; int main(void) { int udp_svr_sk, udp_clt_sk, tcp_svr_sk, tcp_clt_sk; int accept_sk, peeloff_sk; sockaddr_storage_t udp_svr_loop, udp_clt_loop; sockaddr_storage_t tcp_svr_loop, tcp_clt_loop; 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; char *message = "hello, world!\n"; int error; int pf_class; uint32_t ppid; uint32_t stream; sctp_assoc_t udp_svr_associd, udp_clt_associd; struct sctp_assoc_change *sac; char *big_buffer; struct sctp_event_subscribe subscribe; struct sctp_initmsg initmsg; struct sctp_paddrparams paddrparams; struct sctp_sndrcvinfo set_udp_sk_dflt_param, get_udp_sk_dflt_param; struct sctp_sndrcvinfo set_tcp_sk_dflt_param, get_tcp_sk_dflt_param; struct sctp_sndrcvinfo set_udp_assoc_dflt_param; struct sctp_sndrcvinfo get_udp_assoc_dflt_param; struct sctp_sndrcvinfo set_tcp_assoc_dflt_param; struct sctp_sndrcvinfo get_tcp_assoc_dflt_param; struct sctp_sndrcvinfo get_peeloff_assoc_dflt_param; struct sctp_sndrcvinfo get_accept_assoc_dflt_param; struct sctp_paddrinfo pinfo; int dflt_pathmaxrxt; socklen_t optlen, addrlen; struct sctp_status status; struct sctp_assoc_value value; /* 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; udp_svr_loop.v6.sin6_family = AF_INET6; udp_svr_loop.v6.sin6_addr = in6addr_loopback; udp_svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1); udp_clt_loop.v6.sin6_family = AF_INET6; udp_clt_loop.v6.sin6_addr = in6addr_loopback; udp_clt_loop.v6.sin6_port = htons(SCTP_TESTPORT_1+1); tcp_svr_loop.v6.sin6_family = AF_INET6; tcp_svr_loop.v6.sin6_addr = in6addr_loopback; tcp_svr_loop.v6.sin6_port = htons(SCTP_TESTPORT_1+2); tcp_clt_loop.v6.sin6_family = AF_INET6; tcp_clt_loop.v6.sin6_addr = in6addr_loopback; tcp_clt_loop.v6.sin6_port = htons(SCTP_TESTPORT_1+3); #else pf_class = PF_INET; udp_svr_loop.v4.sin_family = AF_INET; udp_svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; udp_svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1); udp_clt_loop.v4.sin_family = AF_INET; udp_clt_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; udp_clt_loop.v4.sin_port = htons(SCTP_TESTPORT_1+1); tcp_svr_loop.v4.sin_family = AF_INET; tcp_svr_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; tcp_svr_loop.v4.sin_port = htons(SCTP_TESTPORT_1+2); tcp_clt_loop.v4.sin_family = AF_INET; tcp_clt_loop.v4.sin_addr.s_addr = SCTP_IP_LOOPBACK; tcp_clt_loop.v4.sin_port = htons(SCTP_TESTPORT_2+3); #endif /* TEST_V6 */ /* Create the two endpoints which will talk to each other. */ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(udp_svr_sk); test_enable_assoc_change(udp_clt_sk); /* Bind these sockets to the test ports. */ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop)); /* Mark udp_svr_sk as being able to accept new associations. */ test_listen(udp_svr_sk, 1); /* TEST #1: SCTP_STATUS socket option. */ /* Make sure that SCTP_STATUS getsockopt on a socket with no * association fails. */ optlen = sizeof(struct sctp_status); memset(&status, 0, optlen); error = getsockopt(udp_svr_sk, SOL_SCTP, SCTP_STATUS, &status, &optlen); if ((error != -1) && (errno != EINVAL)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) on a " "socket with no assoc error:%d errno:%d", error, errno); tst_resm(TPASS, "getsockopt(SCTP_STATUS) on a socket with no assoc"); /* Send the first message. This will create the association. */ outmessage.msg_name = &udp_svr_loop; outmessage.msg_namelen = sizeof(udp_svr_loop); 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(udp_clt_sk, &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 udp_svr_sk. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &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; udp_svr_associd = sac->sac_assoc_id; /* Get the communication up message on udp_clt_sk. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_clt_sk, &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; udp_clt_associd = sac->sac_assoc_id; /* Get the first message which was sent. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); /* Get SCTP_STATUS for udp_clt_sk's given association. */ optlen = sizeof(struct sctp_status); memset(&status, 0, optlen); status.sstat_assoc_id = udp_clt_associd; test_getsockopt(udp_clt_sk, SCTP_STATUS, &status, &optlen); tst_resm(TPASS, "getsockopt(SCTP_STATUS)"); /* Make sure that SCTP_STATUS getsockopt with invalid associd fails. */ optlen = sizeof(struct sctp_status); memset(&status, 0, optlen); status.sstat_assoc_id = udp_svr_associd; error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_STATUS, &status, &optlen); if ((error != -1) && (errno != EINVAL)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) with " "associd error: %d errno:%d", error, errno); tst_resm(TPASS, "getsockopt(SCTP_STATUS) with invalid associd"); /* Make sure that SCTP_STATUS getsockopt with NULL associd fails. */ optlen = sizeof(struct sctp_status); memset(&status, 0, optlen); status.sstat_assoc_id = 0; error = getsockopt(udp_svr_sk, SOL_SCTP, SCTP_STATUS, &status, &optlen); if ((error != -1) && (errno != EINVAL)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS) with " "NULL associd error: %d errno:%d", error, errno); tst_resm(TPASS, "getsockopt(SCTP_STATUS) with NULL associd"); /* Shut down the link. */ close(udp_clt_sk); /* Get the shutdown complete notification. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_SHUTDOWN_COMP); error = 0; close(udp_svr_sk); /* TEST #2: SCTP_EVENTS socket option and SCTP_SHUTDOWN_EVENT * notification. */ /* Create the two endpoints which will talk to each other. */ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(udp_svr_sk); test_enable_assoc_change(udp_clt_sk); /* Bind these sockets to the test ports. */ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop)); /* Mark udp_svr_sk as being able to accept new associations. */ test_listen(udp_svr_sk, 1); /* Get the default events that are enabled on udp_svr_sk. */ optlen = sizeof(subscribe); test_getsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe, &optlen); /* Get the default events that are enabled on udp_clt_sk. */ optlen = sizeof(subscribe); test_getsockopt(udp_clt_sk, SCTP_EVENTS, &subscribe, &optlen); tst_resm(TPASS, "getsockopt(SCTP_EVENTS)"); /* Disable all the events on udp_svr_sk and udp_clt_sk. */ memset(&subscribe, 0, sizeof(struct sctp_event_subscribe)); test_setsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe, sizeof(subscribe)); test_setsockopt(udp_clt_sk, SCTP_EVENTS, &subscribe, sizeof(subscribe)); tst_resm(TPASS, "setsockopt(SCTP_EVENTS)"); /* Get the updated list of enabled events on udp_svr_sk and * udp_clt_sk. */ optlen = sizeof(subscribe); test_getsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe, &optlen); optlen = sizeof(subscribe); test_getsockopt(udp_clt_sk, SCTP_EVENTS, &subscribe, &optlen); /* Send a message. This will create the association. */ outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = strlen(message) + 1; test_sendmsg(udp_clt_sk, &outmessage, 0, strlen(message)+1); /* Get the message which was sent. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, 0, 0); /* Verify that we received the msg without any ancillary data. */ if (inmessage.msg_controllen != 0) tst_brkm(TBROK, tst_exit, "Receive unexpected ancillary" "data"); /* Enable SCTP_SHUTDOWN_EVENTs on udp_svr_sk. */ memset(&subscribe, 0, sizeof(struct sctp_event_subscribe)); subscribe.sctp_shutdown_event = 1; test_setsockopt(udp_svr_sk, SCTP_EVENTS, &subscribe, sizeof(subscribe)); error = 0; /* Shut down the link. */ close(udp_clt_sk); /* Get the SHUTDOWN_EVENT notification on udp_svr_sk. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_shutdown_event), SCTP_SHUTDOWN_EVENT, 0); tst_resm(TPASS, "setsockopt(SCTP_EVENTS) - SCTP_SHUTDOWN_EVENT"); close(udp_svr_sk); /* TEST #3: whether sctp_opt_info equals */ /* Create the two endpoints which will talk to each other. */ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(udp_svr_sk); test_enable_assoc_change(udp_clt_sk); /* Bind these sockets to the test ports. */ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop)); /* Mark udp_svr_sk as being able to accept new associations. */ test_listen(udp_svr_sk, 1); /* Send the first message. This will create the association. */ outmessage.msg_name = &udp_svr_loop; outmessage.msg_namelen = sizeof(udp_svr_loop); 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(udp_clt_sk, &outmessage, 0, strlen(message)+1); /* Get the communication up message on udp_clt_sk. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_clt_sk, &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; udp_clt_associd = sac->sac_assoc_id; /* Compare the SCTP_STATUS result between sctp_opt_info and * getsockopt */ { struct sctp_status status1, status2; memset(&status1, 0, sizeof(status1)); memset(&status2, 0, sizeof(status2)); optlen = sizeof(struct sctp_status); /* Test SCTP_STATUS for udp_clt_sk's given association. */ error = sctp_opt_info(udp_clt_sk,udp_clt_associd,SCTP_STATUS, (char *)&status1, &optlen); if (error != 0) tst_brkm(TBROK, tst_exit, "sctp_opt_info(SCTP_STATUS): %s", strerror(errno)); status2.sstat_assoc_id = udp_clt_associd; error = getsockopt(udp_clt_sk, IPPROTO_SCTP, SCTP_STATUS, (char *)&status2, &optlen); if (error != 0) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_STATUS): %s", strerror(errno)); if (strncmp((char *)&status1, (char *)&status2, optlen)) tst_brkm(TBROK, tst_exit, "sctp_opt_info(SCTP_STAUS)" "doesn't match getsockopt(SCTP_STATUS)"); tst_resm(TPASS, "sctp_opt_info(SCTP_STATUS)"); } error = 0; /* Shut down the link. */ close(udp_svr_sk); close(udp_clt_sk); /* TEST #4: SCTP_INITMSG socket option. */ /* Create a socket. */ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Bind this socket to the test port. */ test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(udp_svr_sk); /* Get the default parameters for association initialization. */ optlen = sizeof(initmsg); test_getsockopt(udp_svr_sk, SCTP_INITMSG, &initmsg, &optlen); tst_resm(TPASS, "getsockopt(SCTP_INITMSG)"); /* Change the parameters for association initialization. */ initmsg.sinit_num_ostreams = 5; initmsg.sinit_max_instreams = 5; initmsg.sinit_max_attempts = 3; initmsg.sinit_max_init_timeo = 30; test_setsockopt(udp_svr_sk, SCTP_INITMSG, &initmsg, sizeof(initmsg)); tst_resm(TPASS, "setsockopt(SCTP_INITMSG)"); /* Get the updated parameters for association initialization. */ optlen = sizeof(initmsg); test_getsockopt(udp_svr_sk, SCTP_INITMSG, &initmsg, &optlen); close(udp_svr_sk); /* TEST #5: SCTP_PEER_ADDR_PARAMS socket option. */ /* Create a socket. */ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); /* Get the default parameters for this endpoint */ optlen = sizeof(paddrparams); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_address.ss_family = AF_INET; test_getsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams, &optlen); dflt_pathmaxrxt = paddrparams.spp_pathmaxrxt; tst_resm(TPASS, "getsockopt(SCTP_PEER_ADDR_PARAMS)"); /* Change the default parameters for this endpoint (socket) */ paddrparams.spp_hbinterval = 1000; paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1; paddrparams.spp_sackdelay = 100; test_setsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); paddrparams.spp_pathmaxrxt = 0; /* Get the updated default parameters for this endpoint. */ optlen = sizeof(paddrparams); test_getsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams, &optlen); if (paddrparams.spp_pathmaxrxt != dflt_pathmaxrxt+1) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "mismatch"); value.assoc_id = 0; optlen = sizeof(value); test_getsockopt(udp_svr_sk, SCTP_DELAYED_ACK_TIME, &value, &optlen); if (value.assoc_value != 100) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DELAYED_ACK_TIME) " "mismatch"); value.assoc_id = 0; value.assoc_value = 250; test_setsockopt(udp_svr_sk, SCTP_DELAYED_ACK_TIME, &value, sizeof(value)); optlen = sizeof(paddrparams); test_getsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams, &optlen); if (paddrparams.spp_sackdelay != 250) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DELAYED_ACK_TIME) " "mismatch"); tst_resm(TPASS, "setsockopt(SCTP_DELAYED_ACK_TIME)"); /* Ensure that prior defaults are preserved for a new endpoint */ udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); optlen = sizeof(paddrparams); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_address.ss_family = AF_INET; test_getsockopt(udp_clt_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams, &optlen); if (paddrparams.spp_pathmaxrxt != dflt_pathmaxrxt) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_PEER_ADDR_PARAMS) " "mismatch"); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS)"); /* Invalid assoc id */ paddrparams.spp_assoc_id = 1234; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid associd error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid associd"); test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop)); test_listen(udp_svr_sk, 5); test_enable_assoc_change(udp_svr_sk); test_enable_assoc_change(udp_clt_sk); /* Do a connect on a UDP-style socket and establish an association. */ test_connect(udp_clt_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); /* Receive the COMM_UP notifications and get the associd's */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &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; paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_hbinterval = 1000; paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1; test_setsockopt(udp_svr_sk, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) - " "one-to-many style valid associd valid address"); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_svr_loop, sizeof(udp_svr_loop)); paddrparams.spp_hbinterval = 1000; paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid transport error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid transport"); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_hbinterval = 1000; paddrparams.spp_pathmaxrxt = dflt_pathmaxrxt+1; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams) - 1); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid parameter length error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid parameter length"); error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_DELAYED_ACK_TIME, &value, sizeof(value) - 1); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DELAYED_ACK_TIME) " "invalid parameter length error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_DELAYED_ACK_TIME) " "- one-to-many style invalid parameter length"); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_sackdelay = 501; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid sack delay error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid sack delay"); value.assoc_id = sac->sac_assoc_id; value.assoc_value = 501; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_DELAYED_ACK_TIME, &value, sizeof(value)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DELAYED_ACK_TIME) " "invalid sack delay error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_DELAYED_ACK_TIME) " "- one-to-many style invalid sack delay"); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_pathmtu = 511; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid path MTU error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid path MTU"); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_flags = SPP_HB_ENABLE | SPP_HB_DISABLE; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid hb enable flags error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid hb enable flags"); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_flags = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid PMTU discovery enable flags error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid PMTU discovery enable flags"); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_assoc_id = sac->sac_assoc_id; memcpy(&paddrparams.spp_address, &udp_clt_loop, sizeof(udp_clt_loop)); paddrparams.spp_flags = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid sack delay enable flags error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid sack delay enable flags"); memset(&paddrparams, 0, sizeof(paddrparams)); paddrparams.spp_flags = SPP_HB_DEMAND; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_PEER_ADDR_PARAMS, &paddrparams, sizeof(paddrparams)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "invalid hb demand error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_PEER_ADDR_PARAMS) " "- one-to-many style invalid hb demand"); close(udp_svr_sk); close(udp_clt_sk); /* TEST #6: SCTP_DEFAULT_SEND_PARAM socket option. */ /* Create and bind 2 UDP-style sockets(udp_svr_sk, udp_clt_sk) and * 2 TCP-style sockets. (tcp_svr_sk, tcp_clt_sk) */ udp_svr_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); udp_clt_sk = test_socket(pf_class, SOCK_SEQPACKET, IPPROTO_SCTP); tcp_svr_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); tcp_clt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(udp_svr_sk); test_enable_assoc_change(udp_clt_sk); test_enable_assoc_change(tcp_svr_sk); test_enable_assoc_change(tcp_clt_sk); test_bind(udp_svr_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); test_bind(udp_clt_sk, &udp_clt_loop.sa, sizeof(udp_clt_loop)); test_bind(tcp_svr_sk, &tcp_svr_loop.sa, sizeof(tcp_svr_loop)); test_bind(tcp_clt_sk, &tcp_clt_loop.sa, sizeof(tcp_clt_loop)); /* Mark udp_svr_sk and tcp_svr_sk as being able to accept new * associations. */ test_listen(udp_svr_sk, 5); test_listen(tcp_svr_sk, 5); /* Set default send parameters on the unconnected UDP-style sockets. */ memset(&set_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_udp_sk_dflt_param.sinfo_ppid = 1000; test_setsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &set_udp_sk_dflt_param, sizeof(set_udp_sk_dflt_param)); memset(&set_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_udp_sk_dflt_param.sinfo_ppid = 1000; test_setsockopt(udp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &set_udp_sk_dflt_param, sizeof(set_udp_sk_dflt_param)); tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style socket"); /* Get default send parameters on the unconnected UDP-style socket. */ memset(&get_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_udp_sk_dflt_param); test_getsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &get_udp_sk_dflt_param, &optlen); /* Verify that the get param matches set param. */ if (set_udp_sk_dflt_param.sinfo_ppid != get_udp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); /* Get default send parameters on the unconnected UDP-style socket. */ memset(&get_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_udp_sk_dflt_param); test_getsockopt(udp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &get_udp_sk_dflt_param, &optlen); /* Verify that the get param matches set param. */ if (set_udp_sk_dflt_param.sinfo_ppid != get_udp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style socket"); /* Verify that trying to set send params with an invalid assoc id * on an UDP-style socket fails. */ memset(&set_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_udp_sk_dflt_param.sinfo_ppid = 1000; /* Invalid assoc id */ set_udp_sk_dflt_param.sinfo_assoc_id = 1234; error = setsockopt(udp_clt_sk, SOL_SCTP, SCTP_DEFAULT_SEND_PARAM, &set_udp_sk_dflt_param, sizeof(set_udp_sk_dflt_param)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DEFAULT_SEND_PARAM) " "invalid associd error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) " "- one-to-many style invalid associd"); /* Do a connect on a UDP-style socket and establish an association. */ test_connect(udp_clt_sk, &udp_svr_loop.sa, sizeof(udp_svr_loop)); /* Receive the COMM_UP notifications and get the associd's */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_svr_sk, &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; udp_svr_associd = sac->sac_assoc_id; inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(udp_clt_sk, &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; udp_clt_associd = sac->sac_assoc_id; /* Verify that trying to set send params with an assoc id not * belonging to the socket on an UDP-style socket fails. */ memset(&set_udp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_udp_assoc_dflt_param.sinfo_ppid = 3000; set_udp_assoc_dflt_param.sinfo_assoc_id = udp_clt_associd; error = setsockopt(udp_svr_sk, SOL_SCTP, SCTP_DEFAULT_SEND_PARAM, &set_udp_assoc_dflt_param, sizeof(set_udp_assoc_dflt_param)); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "setsockopt(SCTP_DEFAULT_SEND_PARAM) " "associd belonging to another socket " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style associd belonging to another socket"); /* Set default send parameters of an association on the listening * UDP-style socket with a valid associd. */ memset(&set_udp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_udp_assoc_dflt_param.sinfo_ppid = 3000; set_udp_assoc_dflt_param.sinfo_assoc_id = udp_svr_associd; test_setsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &set_udp_assoc_dflt_param, sizeof(set_udp_assoc_dflt_param)); tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style valid associd"); /* Get default send parameters of an association on the listening * UDP-style socket with a valid associd. */ memset(&get_udp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); get_udp_assoc_dflt_param.sinfo_assoc_id = udp_svr_associd ; optlen = sizeof(get_udp_assoc_dflt_param); test_getsockopt(udp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &get_udp_assoc_dflt_param, &optlen); /* Verify that the get param matches the set param. */ if (get_udp_assoc_dflt_param.sinfo_ppid != set_udp_assoc_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style valid associd"); /* Get default send parameters of an association on the connected * UDP-style socket with zero associd. This should return the * socket wide default parameters. */ memset(&get_udp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); get_udp_sk_dflt_param.sinfo_assoc_id = 0 ; optlen = sizeof(get_udp_sk_dflt_param); test_getsockopt(udp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &get_udp_sk_dflt_param, &optlen); /* Verify that the get param matches the socket-wide set param. */ if (get_udp_sk_dflt_param.sinfo_ppid != set_udp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style zero associd"); peeloff_sk = test_sctp_peeloff(udp_svr_sk, udp_svr_associd); /* Get default send parameters of an association on the peeled off * UDP-style socket. This should return the association's default * parameters. */ memset(&get_peeloff_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); get_peeloff_assoc_dflt_param.sinfo_assoc_id = 0 ; optlen = sizeof(get_peeloff_assoc_dflt_param); test_getsockopt(peeloff_sk, SCTP_DEFAULT_SEND_PARAM, &get_peeloff_assoc_dflt_param, &optlen); /* Verify that the get param matches the association's set param. */ if (get_peeloff_assoc_dflt_param.sinfo_ppid != set_udp_assoc_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-many style peeled off socket"); /* Set default send parameters on the unconnected TCP-style sockets. */ memset(&set_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_tcp_sk_dflt_param.sinfo_ppid = 2000; /* Invalid assoc id, ignored on a TCP-style socket. */ set_tcp_sk_dflt_param.sinfo_assoc_id = 1234; test_setsockopt(tcp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &set_tcp_sk_dflt_param, sizeof(set_tcp_sk_dflt_param)); /* Set default send parameters on the unconnected TCP-style sockets. */ memset(&set_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_tcp_sk_dflt_param.sinfo_ppid = 2000; /* Invalid assoc id, ignored on a TCP-style socket. */ set_tcp_sk_dflt_param.sinfo_assoc_id = 1234; test_setsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &set_tcp_sk_dflt_param, sizeof(set_tcp_sk_dflt_param)); tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-one style socket"); /* Get default send parameters on the unconnected TCP-style socket. */ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_tcp_sk_dflt_param); test_getsockopt(tcp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &get_tcp_sk_dflt_param, &optlen); /* Verify that the get param matches set param. */ if (set_tcp_sk_dflt_param.sinfo_ppid != get_tcp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); /* Get default send parameters on the unconnected TCP-style socket. */ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_tcp_sk_dflt_param); test_getsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &get_tcp_sk_dflt_param, &optlen); /* Verify that the get param matches set param. */ if (set_tcp_sk_dflt_param.sinfo_ppid != get_tcp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-one style socket"); /* Do a connect on a TCP-style socket and establish an association. */ test_connect(tcp_clt_sk, &tcp_svr_loop.sa, sizeof(tcp_svr_loop)); /* Set default send parameters of an association on the connected * TCP-style socket. */ memset(&set_tcp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); set_tcp_assoc_dflt_param.sinfo_ppid = 4000; set_tcp_assoc_dflt_param.sinfo_assoc_id = 0; test_setsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &set_tcp_assoc_dflt_param, sizeof(set_tcp_assoc_dflt_param)); tst_resm(TPASS, "setsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-one style assoc"); /* Get default send parameters of an association on the connected * TCP-style socket. */ memset(&get_tcp_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_tcp_assoc_dflt_param); test_getsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &get_tcp_assoc_dflt_param, &optlen); if (set_tcp_assoc_dflt_param.sinfo_ppid != get_tcp_assoc_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); /* Get default send parameters on the connected TCP-style socket. */ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_tcp_sk_dflt_param); test_getsockopt(tcp_clt_sk, SCTP_DEFAULT_SEND_PARAM, &get_tcp_sk_dflt_param, &optlen); /* Verify that the get parameters returned matches the set param * set for the association, not the socket-wide param. */ if ((get_tcp_sk_dflt_param.sinfo_ppid == set_tcp_sk_dflt_param.sinfo_ppid) || (get_tcp_sk_dflt_param.sinfo_ppid != set_tcp_assoc_dflt_param.sinfo_ppid)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); /* Get default send parameters on the listening TCP-style socket. */ memset(&get_tcp_sk_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_tcp_sk_dflt_param); test_getsockopt(tcp_svr_sk, SCTP_DEFAULT_SEND_PARAM, &get_tcp_sk_dflt_param, &optlen); /* Verify that the get parameters returned matches the socket-wide * set param. */ if (get_tcp_sk_dflt_param.sinfo_ppid != set_tcp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-one style assoc"); accept_sk = test_accept(tcp_svr_sk, NULL, &addrlen); /* Get default send parameters of an association on the accepted * TCP-style socket. */ memset(&get_accept_assoc_dflt_param, 0, sizeof(struct sctp_sndrcvinfo)); optlen = sizeof(get_accept_assoc_dflt_param); test_getsockopt(accept_sk, SCTP_DEFAULT_SEND_PARAM, &get_accept_assoc_dflt_param, &optlen); error = 0; /* Verify that the get parameters returned matches the socket-wide * set param. */ if (get_tcp_sk_dflt_param.sinfo_ppid != set_tcp_sk_dflt_param.sinfo_ppid) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_DEFAULT_SEND_PARAM) " "mismatch."); tst_resm(TPASS, "getsockopt(SCTP_DEFAULT_SEND_PARAM) - " "one-to-one style accepted socket"); /* TEST #7: SCTP_GET_PEER_ADDR_INFO socket option. */ /* Try 0 associd and 0 addr */ memset(&pinfo, 0, sizeof(pinfo)); optlen = sizeof(pinfo); error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_GET_PEER_ADDR_INFO) " "null associd, null addr error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - " "null associd and null addr"); /* Try valid associd, but 0 addr */ memset(&pinfo, 0, sizeof(pinfo)); optlen = sizeof(pinfo); pinfo.spinfo_assoc_id = udp_clt_associd; error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_GET_PEER_ADDR_INFO) " "valid associd, null addr error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - " "valid associd and null addr"); /* Try valid associd, invalid addr */ memset(&pinfo, 0, sizeof(pinfo)); optlen = sizeof(pinfo); pinfo.spinfo_assoc_id = udp_clt_associd; memcpy(&pinfo.spinfo_address, &udp_clt_loop, sizeof(udp_clt_loop)); error = getsockopt(udp_clt_sk, SOL_SCTP, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen); if ((-1 != error) || (EINVAL != errno)) tst_brkm(TBROK, tst_exit, "getsockopt(SCTP_GET_PEER_ADDR_INFO) " "valid associd, invalid addr error:%d, errno:%d\n", error, errno); tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - " "valid associd and invalid addr"); /* Try valid associd, valid addr */ memset(&pinfo, 0, sizeof(pinfo)); optlen = sizeof(pinfo); pinfo.spinfo_assoc_id = udp_clt_associd; memcpy(&pinfo.spinfo_address, &udp_svr_loop, sizeof(udp_svr_loop)); test_getsockopt(udp_clt_sk, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen); tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - " "valid associd and valid addr"); /* Try valid addr, peeled off socket */ memset(&pinfo, 0, sizeof(pinfo)); optlen = sizeof(pinfo); pinfo.spinfo_assoc_id = 0; memcpy(&pinfo.spinfo_address, &udp_clt_loop, sizeof(udp_clt_loop)); test_getsockopt(peeloff_sk, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen); tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - " "valid associd and valid addr peeled off socket"); /* Try valid addr, TCP-style accept socket */ memset(&pinfo, 0, sizeof(pinfo)); optlen = sizeof(pinfo); pinfo.spinfo_assoc_id = 0; memcpy(&pinfo.spinfo_address, &tcp_clt_loop, sizeof(tcp_clt_loop)); error = test_getsockopt(accept_sk, SCTP_GET_PEER_ADDR_INFO, &pinfo, &optlen); tst_resm(TPASS, "getsockopt(SCTP_GET_PEER_ADDR_INFO) - " "valid associd and valid addr accepted socket"); close(udp_svr_sk); close(udp_clt_sk); close(tcp_svr_sk); close(tcp_clt_sk); close(accept_sk); close(peeloff_sk); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_events.c0000644000175000017500000001444212300634451024521 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This test tests the events for 1-1 style sockets. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * */ #include #include #include #include #include /* needed by linux/sctp.h */ #include #include /* for sockaddr_in */ #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 4; int TST_CNT = 0; int main(int argc, char *argv[]) { int svr_sk, clt_sk,acpt_sk; struct sockaddr_in svr_loop, clt_loop,acpt_loop; struct iovec iov, out_iov; struct msghdr inmessage, outmessage; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; int error; socklen_t len; char *big_buffer; struct sctp_event_subscribe event; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sinfo; char *message = "hello, world!\n"; uint32_t ppid; uint32_t stream; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Initialize the server and client addresses. */ svr_loop.sin_family = AF_INET; svr_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.sin_port = htons(SCTP_TESTPORT_1); clt_loop.sin_family = AF_INET; clt_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop.sin_port = htons(SCTP_TESTPORT_1); /* Create and bind the server socket. */ svr_sk = test_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); test_bind(svr_sk, (struct sockaddr *) &svr_loop, sizeof(svr_loop)); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 3); /* Create the client socket. */ clt_sk = test_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP); event.sctp_data_io_event = 1; event.sctp_association_event = 1; event.sctp_shutdown_event = 1; len = sizeof(struct sctp_event_subscribe); test_setsockopt(svr_sk, SCTP_EVENTS, &event, len); test_setsockopt(clt_sk, SCTP_EVENTS, &event, len); len = sizeof(struct sockaddr_in); test_connect(clt_sk, (struct sockaddr *) &clt_loop, len); acpt_sk = test_accept(svr_sk, (struct sockaddr *) &acpt_loop, &len); /* Build up a msghdr structure we can use for all sending. */ memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &svr_loop; outmessage.msg_namelen = sizeof(svr_loop); 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); /* Send . This will create the association*/ test_sendmsg(clt_sk, &outmessage, 0, strlen(message)+1); memset(&inmessage, 0, sizeof(inmessage)); /* NOW initialize inmessage with enough space for DATA... */ big_buffer = malloc(REALLY_BIG); if (!big_buffer) { DUMP_CORE; } /* Let's do a test to do a recvmsg when we are not listening and * when we have no associations. */ iov.iov_base = big_buffer; iov.iov_len = REALLY_BIG; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); tst_resm(TPASS, "COMM_UP notification on client socket - SUCCESS"); error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); tst_resm(TPASS, "COMM_UP notification on server socket - SUCCESS"); inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, strlen(message) + 1, MSG_EOR, stream, ppid); tst_resm(TPASS, "Data message on server socket - SUCCESS"); close(clt_sk); error = test_recvmsg(acpt_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_shutdown_event), SCTP_SHUTDOWN_EVENT, 0); tst_resm(TPASS, "SHUTDOWN notification on accepted socket - SUCCESS"); close(svr_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/Makefile.am0000644000175000017500000001123112300634451022675 0ustar michaelmichael# Include these two in all the Makefile.am's!!! include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules include $(top_srcdir)/Makefile.dirs # General compilation flags AM_CPPFLAGS = -I. -I$(top_srcdir)/src/include -I$(top_srcdir)/src/testlib \ -g -O2 -fno-strict-aliasing -Wall -Wstrict-prototypes \ -Wimplicit-function-declaration AM_LDFLAGS = -lpthread LDADD = $(top_builddir)/src/testlib/libsctputil.la \ $(top_builddir)/src/lib/libsctp.la V6FLAGS = -DCONFIG_IPV6=1 -DTEST_V6=1 ${DEFS} ${INCLUDES} ${CFLAGS} # Test programs and libraries to build PASSING_KERN_TESTS = \ test_assoc_abort \ test_assoc_shutdown \ test_autoclose \ test_basic \ test_fragments \ test_inaddr_any \ test_peeloff \ test_sockopt \ test_connect \ test_connectx \ test_recvmsg \ test_timetolive \ test_sctp_sendrecvmsg \ test_getname \ test_tcp_style\ test_1_to_1_socket_bind_listen \ test_1_to_1_accept_close \ test_1_to_1_connect \ test_1_to_1_connectx \ test_1_to_1_send \ test_1_to_1_sendto \ test_1_to_1_sendmsg \ test_1_to_1_recvfrom \ test_1_to_1_recvmsg \ test_1_to_1_shutdown \ test_1_to_1_sockopt \ test_1_to_1_addrs \ test_1_to_1_nonblock \ test_1_to_1_rtoinfo \ test_1_to_1_events \ test_1_to_1_threads \ test_1_to_1_initmsg_connect PASSING_V6_KERN_TESTS = \ test_basic_v6 \ test_sockopt_v6 \ test_fragments_v6 \ test_inaddr_any_v6 \ test_peeloff_v6 \ test_timetolive_v6 \ test_sctp_sendrecvmsg_v6 \ test_getname_v6 \ test_tcp_style_v6 noinst_PROGRAMS = ${PASSING_KERN_TESTS} ${PASSING_V6_KERN_TESTS} $(top_builddir)/src/lib/libsctp.la: $(MAKE) -C $(top_builddir)/src/lib libsctp.la $(top_builddir)/src/testlib/libsctputil.la: $(MAKE) -C $(top_builddir)/src/testlib libsctputil.la # These are tests for live kernels which pass. v4test: ${PASSING_KERN_TESTS} @for a in $^; \ do \ echo "./$$a"; \ if ./$$a; \ then \ echo "$$a passes"; \ echo ""; \ else \ echo "$$a fails"; \ exit 1; \ fi; \ sleep 1; \ done @echo "Hoody hoo!" # These are tests for live kernels which pass. v6test: ${PASSING_V6_KERN_TESTS} @for a in $^; \ do \ echo "./$$a"; \ if ./$$a; \ then \ echo "$$a passes"; \ echo ""; \ else \ echo "$$a fails"; \ exit 1; \ fi; \ sleep 1; \ done @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_timetolive_SOURCES = test_timetolive.c test_sctp_sendrecvmsg_SOURCES = test_sctp_sendrecvmsg.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 test_1_to_1_connect_SOURCES = test_1_to_1_connect.c test_1_to_1_connectx_SOURCES = test_1_to_1_connectx.c test_1_to_1_send_SOURCES = test_1_to_1_send.c test_1_to_1_sendto_SOURCES = test_1_to_1_sendto.c test_1_to_1_sendmsg_SOURCES = test_1_to_1_sendmsg.c test_1_to_1_recvfrom_SOURCES = test_1_to_1_recvfrom.c test_1_to_1_recvmsg_SOURCES = test_1_to_1_recvmsg.c test_1_to_1_shutdown_SOURCES = test_1_to_1_shutdown.c test_1_to_1_sockopt_SOURCES = test_1_to_1_sockopt.c test_1_to_1_addrs_SOURCES = test_1_to_1_addrs.c test_1_to_1_nonblock_SOURCES = test_1_to_1_nonblock.c test_1_to_1_rtoinfo_SOURCES = test_1_to_1_rtoinfo.c test_1_to_1_events_SOURCES = test_1_to_1_events.c test_1_to_1_threads_SOURCES = test_1_to_1_threads.c test_1_to_1_initmsg_connect_SOURCES = test_1_to_1_initmsg_connect.c # # Specifying objects rules for "v6test" # test_basic_v6_SOURCES = test_basic.c test_basic_v6_CFLAGS = ${V6FLAGS} test_sockopt_v6_SOURCES = test_sockopt.c test_sockopt_v6_CFLAGS = ${V6FLAGS} test_fragments_v6_SOURCES = test_fragments.c test_fragments_v6_CFLAGS = ${V6FLAGS} test_inaddr_any_v6_SOURCES = test_inaddr_any.c test_inaddr_any_v6_CFLAGS = ${V6FLAGS} test_peeloff_v6_SOURCES = test_peeloff.c test_peeloff_v6_CFLAGS = ${V6FLAGS} test_timetolive_v6_SOURCES = test_timetolive.c test_timetolive_v6_CFLAGS = ${V6FLAGS} test_sctp_sendrecvmsg_v6_SOURCES = test_sctp_sendrecvmsg.c test_sctp_sendrecvmsg_v6_CFLAGS = ${V6FLAGS} test_getname_v6_SOURCES = test_getname.c test_getname_v6_CFLAGS = ${V6FLAGS} test_tcp_style_v6_SOURCES = test_tcp_style.c test_tcp_style_v6_CFLAGS = ${V6FLAGS} lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_recvfrom.c0000644000175000017500000001504212300634451025035 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the recvfrom () call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: Invalid message pointer * TEST4: On a listening socket * TEST5: Reading on a socket that received SHUTDOWN * TEST6: Reading the pending message on socket that received SHUTDOWN * TEST7: No more message and association is shutdown * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 7; int TST_CNT = 0; int main(int argc, char *argv[]) { int msg_count; socklen_t len; int sk,pf_class,lstn_sk,acpt_sk, flag; char *message = "hello, world!\n"; char *message_rcv; int count; int fd, err_no = 0; char filename[21]; struct sockaddr_in conn_addr,lstn_addr,svr_addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); message_rcv = malloc(512); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); msg_count = (strlen(message) + 1); flag = MSG_NOSIGNAL; /*Sending the message*/ count = test_send(sk, message, msg_count, flag); /*recvfrom () TEST1: Bad socket descriptor, EBADF Expected error*/ count = recvfrom(-1, message_rcv, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "recvfrom with a bad socket " "descriptor count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvfrom() with a bad socket descriptor - EBADF"); /*recvfrom () TEST2: Invalid socket , ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); count = recvfrom(fd, message_rcv, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count == -1) err_no = errno; close(fd); unlink(filename); if (count != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "recvfrom with invalid socket " "count:%d, errno:%d", count, err_no); tst_resm(TPASS, "recvfrom() with invalid socket - ENOTSOCK"); /*recvfrom () TEST3: Invalid message pointer EFAULT, Expected error*/ count = recvfrom(acpt_sk, (char *)-1, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "recvfrom with invalid message " "pointer count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvfrom() with invalid message ptr - EFAULT"); /*TEST4: recvfrom on listening socket,ENOTCONN Expected error*/ count = recvfrom(lstn_sk, message_rcv, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count != -1 || errno != ENOTCONN) tst_brkm(TBROK, tst_exit, "recvfrom on listening socket " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvfrom() on listening socket - ENOTCONN"); count = test_send(acpt_sk, message, msg_count, flag); test_shutdown(sk, SHUT_WR); /*recvfrom () TEST5:reading on a socket that received SHUTDOWN*/ count = recvfrom(acpt_sk, message_rcv, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count < 0) tst_brkm(TBROK, tst_exit, "recvfrom on a socket that has " "received shutdown count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvfrom() on a socket that has received shutdown - " "EOF"); /*recvfrom () TEST6:reading the pending message on socket that sent SHUTDOWN*/ count = recvfrom(sk, message_rcv, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count < 0) tst_brkm(TBROK, tst_exit, "recvfrom on a socket with pending " "message that has sent shutdown count:%d, errno:%d", count, errno); tst_resm(TPASS, "recvfrom() on a socket with pending message that has " "sent shutdown - SUCCESS"); /*recvfrom () TEST7: No more message and association is shutdown, ENOTCONN Expected error*/ count = recvfrom(sk, message_rcv, msg_count, flag, (struct sockaddr *)&svr_addr, &len); if (count != -1 || errno != ENOTCONN) tst_brkm(TBROK, tst_exit, "recvfrom on a socket with no " "pending messages and has sent shutdown count:%d, " "errno:%d", count, errno); tst_resm(TPASS, "recvfrom() on a socket with no pending messages and " " has sent shutdown - ENOTCONN"); close(sk); close(lstn_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_recvmsg.c0000644000175000017500000001204012300634451023511 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2002, 2003 * Copyright (c) 1999-2001 Motorola, Inc. * * This file is part of the SCTP kernel Implementation * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Written or modified by: * Sridhar Samudrala * * Any bugs reported to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ /* This is a kernel test to verify * 1. MSG_EOR flag is set correctly when a single message is read using multiple * recvmsg() calls. * 2. MSG_PEEK support. */ #include #include #include #include #include #include #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 2; int TST_CNT = 0; int main(int argc, char *argv[]) { int svr_sk, clt_sk; struct sockaddr_in svr_loop, clt_loop; struct iovec iov, out_iov; struct msghdr inmessage, outmessage; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; int error, msglen, i; char *big_buffer; void *msg_buf; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); /* Initialize the server and client addresses. */ svr_loop.sin_family = AF_INET; svr_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK; svr_loop.sin_port = htons(SCTP_TESTPORT_1); clt_loop.sin_family = AF_INET; clt_loop.sin_addr.s_addr = SCTP_IP_LOOPBACK; clt_loop.sin_port = htons(SCTP_TESTPORT_2); /* Create and bind the server socket. */ svr_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(svr_sk, (struct sockaddr *)&svr_loop, sizeof(svr_loop)); /* Mark server socket as being able to accept new associations. */ test_listen(svr_sk, 1); /* Create and bind the client sockets. */ clt_sk = test_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); test_bind(clt_sk, (struct sockaddr *)&clt_loop, sizeof(clt_loop)); /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ test_enable_assoc_change(svr_sk); test_enable_assoc_change(clt_sk); /* Send a message. This will create the association. */ memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &svr_loop; outmessage.msg_namelen = sizeof(svr_loop); outmessage.msg_iov = &out_iov; outmessage.msg_iovlen = 1; msg_buf = test_build_msg(30000); outmessage.msg_iov->iov_base = msg_buf; outmessage.msg_iov->iov_len = 30000; test_sendmsg(clt_sk, &outmessage, 0, 30000); /* Initialize inmessage for all receives. */ big_buffer = test_malloc(REALLY_BIG); memset(&inmessage, 0, sizeof(inmessage)); iov.iov_base = big_buffer; iov.iov_len = 2000; inmessage.msg_iov = &iov; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; /* Receive COMM_UP on clt_sk. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(clt_sk, &inmessage, 0); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); /* Receive COMM_UP on svr_sk. */ inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_notification(&inmessage, error, sizeof(struct sctp_assoc_change), SCTP_ASSOC_CHANGE, SCTP_COMM_UP); /* Read the 30000 byte message using multiple recvmsg() calls in a * loop with 2000 bytes per read. */ for (i = 0, msglen = 30000; i < 15; i++, msglen-=2000) { iov.iov_len = REALLY_BIG; inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_PEEK); test_check_msg_data(&inmessage, error, msglen, MSG_EOR, 0, 0); iov.iov_len = 2000; inmessage.msg_controllen = sizeof(incmsg); error = test_recvmsg(svr_sk, &inmessage, MSG_WAITALL); test_check_msg_data(&inmessage, error, 2000, ((i==14)?MSG_EOR:0), 0, 0); } tst_resm(TPASS, "recvmsg with MSG_PEEK flag"); tst_resm(TPASS, "MSG_EOR in msg_flags set correctly"); close(svr_sk); close(clt_sk); /* Indicate successful completion. */ return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_sendmsg.c0000644000175000017500000003106512300634451024655 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the sendmsg() call for 1-1 style sockets * * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: On a listening socket * TEST4: Invalid iovec pointer * TEST5: Invalid iovec length * TEST6: Invalid msghdr pointer * TEST7: Invalid sinfo flags * TEST8: SCTP_EOF flag set * TEST9: SCTP_ABORT flag set * TEST10: On a closed association * * TEST11: Sending data from server socket to client socket * TEST12: Sending data from client socket to server socket * TEST13: Sending data from unconnected client to server * TEST14: Sending a message on SHUT_RD socket * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 14; int TST_CNT = 0; int main(int argc, char *argv[]) { socklen_t len; int msg_count; int sk,sk1,pf_class,lstn_sk,acpt_sk,acpt1_sk, flag; struct msghdr outmessage; char *message = "hello, world!\n"; struct sctp_sndrcvinfo *sinfo; int count; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct iovec out_iov; struct msghdr inmessage; char * buffer_rcv; struct sockaddr_in conn_addr,lstn_addr,svr_addr; struct iovec iov_rcv; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; int fd, err_no = 0; char filename[21]; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &conn_addr; outmessage.msg_namelen = sizeof(conn_addr); 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)); outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = strlen(message) + 1; flag = MSG_NOSIGNAL; /*sendmsg () TEST1: Bad socket descriptor, EBADF Expected error*/ count = sendmsg(-1, &outmessage, flag); if (count != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "sendmsg with a bad socket " "descriptor count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with a bad socket descriptor - EBADF"); /*sendmsg () TEST2: Invalid socket, ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); count = sendmsg(fd, &outmessage, flag); if (count == -1) err_no = errno; close(fd); unlink(filename); if (count != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "sendmsg with invalid socket " "count:%d, errno:%d", count, err_no); tst_resm(TPASS, "sendmsg() with invalid socket - ENOTSOCK"); /*sendmsg () TEST3: sendmsg on listening socket, EPIPE Expected error*/ count = sendmsg(lstn_sk, &outmessage, flag); if (count != -1 || errno != EPIPE) tst_brkm(TBROK, tst_exit, "sendmsg on a listening socket " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() on a listening socket - EPIPE"); /*sendmsg () TEST4: Invalid iovec pointer EFAULT, Expected error*/ outmessage.msg_iov = (struct iovec *)-1; count = sendmsg(sk, &outmessage, flag); if (count != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "sendmsg with invalid iovec " "pointer count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with invalid iovec ptr - EFAULT"); outmessage.msg_iov = &out_iov; /*sendmsg () TEST5: Invalid iovec count EINVAL, Expected error*/ outmessage.msg_iovlen = 0; count = sendmsg(sk, &outmessage, flag); if (count != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sendmsg with invalid iovec " "length count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with invalid iovec length - EINVAL"); outmessage.msg_iovlen = 1; /*sendmsg () TEST6: Invalid msghdr pointer EFAULT, Expected error*/ count = sendmsg(sk, (struct msghdr *)-1, flag); if (count != -1 || errno != EFAULT) tst_brkm(TBROK, tst_exit, "sendmsg with invalid msghdr " "pointer count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with invalid msghdr ptr - EFAULT"); /*sendmsg () TEST7: Invalid sinfo flag EINVAL, Expected error*/ sinfo->sinfo_flags = 999; count = sendmsg(sk, &outmessage, -1); if (count != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sendmsg with invalid sinfo " "flags count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with invalid sinfo flags - EINVAL"); /*sendmsg () TEST8: SCTP_EOF flag EINVAL, Expected error*/ sinfo->sinfo_flags = SCTP_EOF; count = sendmsg(sk, &outmessage, flag); if (count != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_EOF flag " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with SCTP_EOF flag - EINVAL"); /*sendmsg () TEST9: SCTP_ABORT flag EINVAL, Expected error*/ sinfo->sinfo_flags = SCTP_ABORT; count = sendmsg(sk, &outmessage, flag); if (count != -1 || errno != EINVAL) tst_brkm(TBROK, tst_exit, "sendmsg with SCTP_ABORT flag " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() with SCTP_ABORT flag - EINVAL"); sinfo->sinfo_flags = 0; test_connect(sk1, (struct sockaddr *) &lstn_addr, len); test_sendmsg(sk1, &outmessage, flag, strlen(message)+1); close(sk1); acpt1_sk = test_accept(lstn_sk, (struct sockaddr *)&conn_addr, &len); /*sendmsg () TEST10:sendmsg on closed association, EPIPE Expected error*/ count = sendmsg(acpt1_sk, &outmessage, flag); if (count != -1 || errno != EPIPE) tst_brkm(TBROK, tst_exit, "sendmsg on a closed association " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() on a closed association - EPIPE"); close(acpt1_sk); close(sk); close(lstn_sk); close(acpt_sk); sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); flag = MSG_NOSIGNAL; test_connect(sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &svr_addr; outmessage.msg_namelen = sizeof(svr_addr); 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)); outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = strlen(message) + 1; memset(&inmessage, 0, sizeof(inmessage)); buffer_rcv = malloc(REALLY_BIG); iov_rcv.iov_base = buffer_rcv; iov_rcv.iov_len = REALLY_BIG; inmessage.msg_iov = &iov_rcv; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); msg_count = strlen(message) + 1; /*sendmsg() TEST11: Sending data from server socket to client socket*/ count = sendmsg(acpt_sk, &outmessage, flag); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendmsg from accept socket to " "client count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() from accept socket to client - SUCCESS"); count = test_recvmsg(sk, &inmessage, flag); test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0); outmessage.msg_name = &conn_addr; outmessage.msg_namelen = sizeof(conn_addr); /*sendmsg() TEST12: Sending data from client socket to server socket*/ count = sendmsg(sk, &outmessage, flag); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendmsg from client to server " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() from client to server - SUCCESS"); count = test_recvmsg(acpt_sk, &inmessage, flag); test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0); outmessage.msg_name = &conn_addr; outmessage.msg_namelen = sizeof(conn_addr); close(sk); close(acpt_sk); sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*sendmsg() TEST13: Sending data from unconnected client socket to server socket*/ count = sendmsg(sk1, &outmessage, flag); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendmsg from unconnected client to " "server count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() from unconnected clt to server - SUCCESS"); acpt_sk = test_accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); count = test_recvmsg(acpt_sk, &inmessage, flag); test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0); test_shutdown(sk1, SHUT_RD); /*sendmsg() TEST14: Sending a message on SHUT_RD socket*/ count = sendmsg(sk1, &outmessage, flag); if (count != msg_count) tst_brkm(TBROK, tst_exit, "sendmsg on a SHUT_RD socket " "count:%d, errno:%d", count, errno); tst_resm(TPASS, "sendmsg() on a SHUT_RD socket - SUCCESS"); count = test_recvmsg(acpt_sk, &inmessage, flag); test_check_msg_data(&inmessage, count, msg_count, MSG_EOR, 0, 0); close(sk1); close(lstn_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_addrs.c0000644000175000017500000002264212300634451024313 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the sctp_getladdrs (), sctp_freealddrs (), * sctp_getpaddrs (), sctp_freeapaddrs () for 1-1 style sockets * * sctp_getladdrs () Tests: * ----------------------- * TEST1: Bad socket descriptor * TEST2: Invalid socket * TEST3: Socket of different protocol * TEST4: Getting the local addresses * * sctp_freealddrs () Tests: * ------------------------ * TEST5: Freeing the local address * * sctp_getpaddrs () Tests: * ----------------------- * TEST6: Bad socket descriptor * TEST7: Invalid socket * TEST8: Socket of different protocol * TEST9: Getting the peers addresses * * sctp_freeapddrs () Tests: * ------------------------ * TEST10: Freeing the peer's address * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 10; int TST_CNT = 0; int main(int argc, char *argv[]) { int error; socklen_t len; int lstn_sk,clnt_sk,acpt_sk,pf_class,sk1; struct msghdr outmessage; struct msghdr inmessage; char *message = "hello, world!\n"; struct iovec iov_rcv; struct sctp_sndrcvinfo *sinfo; int msg_count; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct iovec out_iov; char * buffer_rcv; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; struct sockaddr *laddrs, *paddrs; int fd, err_no = 0; char filename[21]; struct sockaddr_in conn_addr,lstn_addr,acpt_addr; struct sockaddr_in *addr; /* Rather than fflush() throughout the code, set stdout to * be unbuffered. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; /*Creating a regular socket*/ clnt_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); /*Creating a listen socket*/ lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening many sockets as we are calling too many connect here*/ test_listen(lstn_sk, 1); len = sizeof(struct sockaddr_in); test_connect(clnt_sk, (struct sockaddr *) &conn_addr, len); acpt_sk = test_accept(lstn_sk, (struct sockaddr *) &acpt_addr, &len); memset(&inmessage, 0, sizeof(inmessage)); buffer_rcv = malloc(REALLY_BIG); iov_rcv.iov_base = buffer_rcv; iov_rcv.iov_len = REALLY_BIG; inmessage.msg_iov = &iov_rcv; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); msg_count = strlen(message) + 1; memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &lstn_addr; outmessage.msg_namelen = sizeof(lstn_addr); 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)); outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = msg_count; test_sendmsg(clnt_sk, &outmessage, MSG_NOSIGNAL, msg_count); test_recvmsg(acpt_sk, &inmessage, MSG_NOSIGNAL); /*sctp_getladdrs() TEST1: Bad socket descriptor, EBADF Expected error*/ error = sctp_getladdrs(-1, 0, &laddrs); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "sctp_getladdrs with a bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getladdrs() with a bad socket descriptor - " "EBADF"); /*sctp_getladdrs() TEST2: Invalid socket, ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = sctp_getladdrs(fd, 0, &laddrs); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "sctp_getladdrs with invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "sctp_getladdrs() with invalid socket - ENOTSOCK"); /*sctp_getladdrs() TEST3: socket of different protocol EOPNOTSUPP Expected error*/ sk1 = socket(pf_class, SOCK_STREAM, IPPROTO_IP); error = sctp_getladdrs(sk1, 0, &laddrs); if (error != -1 || errno != EOPNOTSUPP) tst_brkm(TBROK, tst_exit, "sctp_getladdrs with socket of " "different protocol error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getladdrs() with socket of different protocol - " "EOPNOTSUPP"); /*sctp_getladdrs() TEST4: Getting the local addresses*/ error = sctp_getladdrs(lstn_sk, 0, &laddrs); if (error < 0) tst_brkm(TBROK, tst_exit, "sctp_getladdrs with valid socket " "error:%d, errno:%d", error, errno); addr = (struct sockaddr_in *)laddrs; if (addr->sin_port != lstn_addr.sin_port || addr->sin_family != lstn_addr.sin_family || addr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr) tst_brkm(TBROK, tst_exit, "sctp_getladdrs comparision failed"); tst_resm(TPASS, "sctp_getladdrs() - SUCCESS"); /*sctp_freealddrs() TEST5: freeing the local address*/ if ((sctp_freeladdrs(laddrs)) < 0) tst_brkm(TBROK, tst_exit, "sctp_freeladdrs " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_freeladdrs() - SUCCESS"); /*sctp_getpaddrs() TEST6: Bad socket descriptor, EBADF Expected error*/ error = sctp_getpaddrs(-1, 0, &paddrs); if (error != -1 || errno != EBADF) tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with a bad socket " "descriptor error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getpaddrs() with a bad socket descriptor - " "EBADF"); /*sctp_getpaddrs() TEST7: Invalid socket, ENOTSOCK Expected error*/ strcpy(filename, "/tmp/sctptest.XXXXXX"); fd = mkstemp(filename); if (fd == -1) tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s", filename, strerror(errno)); error = sctp_getpaddrs(fd, 0, &paddrs); if (error == -1) err_no = errno; close(fd); unlink(filename); if (error != -1 || err_no != ENOTSOCK) tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with invalid socket " "error:%d, errno:%d", error, err_no); tst_resm(TPASS, "sctp_getpaddrs() with invalid socket - ENOTSOCK"); /*sctp_getpaddrs() TEST8: socket of different protocol EOPNOTSUPP Expected error*/ error = sctp_getpaddrs(sk1, 0, &laddrs); if (error != -1 || errno != EOPNOTSUPP) tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with socket of " "different protocol error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_getpaddrs() with socket of different protocol - " "EOPNOTSUPP"); /*sctp_getpaddrs() TEST9: Getting the peer addresses*/ error = sctp_getpaddrs(acpt_sk, 0, &paddrs); if (error < 0) tst_brkm(TBROK, tst_exit, "sctp_getpaddrs with valid socket " "error:%d, errno:%d", error, errno); addr = (struct sockaddr_in *)paddrs; if (addr->sin_port != acpt_addr.sin_port || addr->sin_family != acpt_addr.sin_family || addr->sin_addr.s_addr != acpt_addr.sin_addr.s_addr) tst_brkm(TBROK, tst_exit, "sctp_getpaddrs comparision failed"); tst_resm(TPASS, "sctp_getpaddrs() - SUCCESS"); /*sctp_freeapddrs() TEST10: freeing the peer address*/ if ((sctp_freepaddrs(paddrs)) < 0) tst_brkm(TBROK, tst_exit, "sctp_freepaddrs " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "sctp_freepaddrs() - SUCCESS"); close(clnt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_timetolive.c0000644000175000017500000003245412300634451024237 0ustar michaelmichael/* 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 * * 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 * Sridhar Samudrala */ /* * This is a basic functional test for the SCTP kernel * implementation of sndrcvinfo.sinfo_timetolive. * * 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. * 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 #include #include #include #include #include #include #include #include #include #include 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; uint32_t ppid; uint32_t stream; sctp_assoc_t associd1; struct sctp_assoc_change *sac; struct sctp_event_subscribe subscribe; char *big_buffer; int offset; struct sctp_send_failed *ssf; socklen_t 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; 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; 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 advertise rcvbuf/2 as * our initial rwnd */ 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); #if 0 sac = (struct sctp_assoc_change *)iov.iov_base; associd2 = sac->sac_assoc_id; #endif /* 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; /* 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_timetolive = 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_timetolive = 2000; 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_timetolive = 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_timetolive = 2000; 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; } lksctp-tools-1.0.16+dfsg.orig/src/func_tests/test_1_to_1_nonblock.c0000644000175000017500000001576212300634451025030 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 2003 Hewlett-Packard Development Company, L.P * (C) Copyright IBM Corp. 2004 * * This file has test cases to test the Non-Blocking mode of connect(), * accept() and recvmsg() calls. * * TEST1: Non blocking accept return EAGAIN if connect is not called * TEST2: Non blocking connect should return EINPROGRESS * TEST3: accept() passes when connect called in Non-blocking mode * TEST4: Non blocking recvmsg should return EAGAIN * TEST5: recvmsg() should succeed if data present to receive in non blocking * mode * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release * */ #include #include #include #include #include #include #include #include /* for sockaddr_in */ #include #include #include #include #include #include char *TCID = __FILE__; int TST_TOTAL = 5; int TST_CNT = 0; int main(int argc, char *argv[]) { int error,msg_count; socklen_t len; int sk,pf_class,lstn_sk,acpt_sk,flag,cflag,sflag; struct msghdr outmessage; struct msghdr inmessage; char *message = "hello, world!\n"; struct iovec iov_rcv; struct sctp_sndrcvinfo *sinfo; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct iovec out_iov; char * buffer_rcv; char incmsg[CMSG_SPACE(sizeof(sctp_cmsg_data_t))]; struct sockaddr_in conn_addr,lstn_addr,svr_addr; /* Rather than fflush() throughout the code, set stdout to * be unbufferd */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); pf_class = PF_INET; sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); lstn_sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP); conn_addr.sin_family = AF_INET; conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; conn_addr.sin_port = htons(SCTP_TESTPORT_1); lstn_addr.sin_family = AF_INET; lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK; lstn_addr.sin_port = htons(SCTP_TESTPORT_1); /*Binding the listen socket*/ test_bind(lstn_sk, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr)); /*Listening the socket*/ test_listen(lstn_sk, 10); len = sizeof(struct sockaddr_in); flag = MSG_NOSIGNAL; /*Setting server socket non-blocking*/ sflag = fcntl(lstn_sk, F_GETFL, 0); if (sflag < 0) tst_brkm(TBROK, tst_exit, "fcnt F_GETFL failed " "sflag:%d, errno:%d", sflag, errno); error = fcntl(lstn_sk, F_SETFL, sflag | O_NONBLOCK); if (error < 0) tst_brkm(TBROK, tst_exit, "fcnt F_SETFL failed " "error:%d, errno:%d", error, errno); /* TEST1: accept should return EAGAIN instead blocking. */ error = accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); if (error != -1 || errno != EAGAIN) tst_brkm(TBROK, tst_exit, "non-blocking accept " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "non-blocking accept() - EAGAIN"); /* TEST2: Non Block connect should return EINPROGRESS */ /*Set client socket as non-blocking*/ cflag = fcntl(sk, F_GETFL, 0); if (cflag < 0) tst_brkm(TBROK, tst_exit, "fcnt F_GETFL failed " "cflag:%d, errno:%d", cflag, errno); error = fcntl(sk, F_SETFL, sflag | O_NONBLOCK); if (error < 0) tst_brkm(TBROK, tst_exit, "fcnt F_SETFL failed " "error:%d, errno:%d", error, errno); error = connect(sk, (const struct sockaddr *) &conn_addr, len); if (error != -1 || errno != EINPROGRESS) tst_brkm(TBROK, tst_exit, "non-blocking connect " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "non-blocking connect() - EINPROGRESS"); /* TEST3: Now that connect() called, accept will succeed */ acpt_sk = accept(lstn_sk, (struct sockaddr *)&svr_addr, &len); if (acpt_sk < 0) tst_brkm(TBROK, tst_exit, "accept after a non-blocking connect " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "accept() after a non-blocking connect - SUCCESS"); memset(&outmessage, 0, sizeof(outmessage)); outmessage.msg_name = &svr_addr; outmessage.msg_namelen = sizeof(svr_addr); 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)); outmessage.msg_iov->iov_base = message; outmessage.msg_iov->iov_len = strlen(message) + 1; memset(&inmessage, 0, sizeof(inmessage)); buffer_rcv = malloc(REALLY_BIG); iov_rcv.iov_base = buffer_rcv; iov_rcv.iov_len = REALLY_BIG; inmessage.msg_iov = &iov_rcv; inmessage.msg_iovlen = 1; inmessage.msg_control = incmsg; inmessage.msg_controllen = sizeof(incmsg); msg_count = strlen(message) + 1; /* TEST4: recvmsg() should return EAGAIN instead blocking */ error = recvmsg(sk, &inmessage, MSG_WAITALL); if ( error != -1 || errno != EAGAIN) tst_brkm(TBROK, tst_exit, "non-blocking recvmsg " "error:%d, errno:%d", error, errno); tst_resm(TPASS, "non-blocking recvmsg() - EAGAIN"); test_sendmsg(acpt_sk, &outmessage, flag, msg_count); /* TEST5: recvmsg() should succeed now as data is available. */ error = test_recvmsg(sk, &inmessage, flag); test_check_msg_data(&inmessage, error, msg_count, MSG_EOR, 0, 0); tst_resm(TPASS, "non-blocking recvmsg() when data is available - " "SUCCESS"); close(lstn_sk); close(acpt_sk); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/include/0000755000175000017500000000000012300634451020111 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/include/netinet/0000755000175000017500000000000012300634451021557 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/include/netinet/sctp.h0000644000175000017500000006304012300634451022704 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * sctp.h * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * Linux Kernel SCTP Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with SCTP in kernel. * * This header represents the structures and constants needed to support * the SCTP Extension to the Sockets API. * * (C) Copyright IBM Corp. 2001, 2004 * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * * Written or modified by: * La Monte H.P. Yarroll * R. Stewart * K. Morneau * Q. Xie * Karl Knutson * Jon Grimm * Daisy Chang * Inaky Perez-Gonzalez * Sridhar Samudrala * Vlad Yasevich */ #ifndef __linux_sctp_h__ #define __linux_sctp_h__ #include #include #include __BEGIN_DECLS typedef __s32 sctp_assoc_t; /* Socket option layer for SCTP */ #ifndef SOL_SCTP #define SOL_SCTP 132 #endif #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif /* 9. Preprocessor constants */ #define HAVE_SCTP #define HAVE_KERNEL_SCTP #define HAVE_SCTP_MULTIBUF #define HAVE_SCTP_NOCONNECT #define HAVE_SCTP_PRSCTP #define HAVE_SCTP_ADDIP #define HAVE_SCTP_CANSET_PRIMARY /* The following symbols come from the Sockets API Extensions for * SCTP . */ #define SCTP_RTOINFO 0 #define SCTP_ASSOCINFO 1 #define SCTP_INITMSG 2 #define SCTP_NODELAY 3 /* Get/set nodelay option. */ #define SCTP_AUTOCLOSE 4 #define SCTP_SET_PEER_PRIMARY_ADDR 5 #define SCTP_PRIMARY_ADDR 6 #define SCTP_ADAPTATION_LAYER 7 #define SCTP_DISABLE_FRAGMENTS 8 #define SCTP_PEER_ADDR_PARAMS 9 #define SCTP_DEFAULT_SEND_PARAM 10 #define SCTP_EVENTS 11 #define SCTP_I_WANT_MAPPED_V4_ADDR 12 /* Turn on/off mapped v4 addresses */ #define SCTP_MAXSEG 13 /* Get/set maximum fragment. */ #define SCTP_STATUS 14 #define SCTP_GET_PEER_ADDR_INFO 15 #define SCTP_DELAYED_ACK_TIME 16 #define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME #define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME #define SCTP_CONTEXT 17 #define SCTP_FRAGMENT_INTERLEAVE 18 #define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */ #define SCTP_MAX_BURST 20 /* Set/Get max burst */ #define SCTP_AUTH_CHUNK 21 /* Set only: add a chunk type to authenticate */ #define SCTP_HMAC_IDENT 22 #define SCTP_AUTH_KEY 23 #define SCTP_AUTH_ACTIVE_KEY 24 #define SCTP_AUTH_DELETE_KEY 25 #define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */ #define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */ #define SCTP_GET_ASSOC_NUMBER 28 /* Read only */ /* Internal Socket Options. Some of the sctp library functions are * implemented using these socket options. */ #define SCTP_SOCKOPT_BINDX_ADD 100 /* BINDX requests for adding addrs */ #define SCTP_SOCKOPT_BINDX_REM 101 /* BINDX requests for removing addrs. */ #define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */ /* Options 104-106 are deprecated and removed. Do not use this space */ #define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */ #define SCTP_GET_PEER_ADDRS 108 /* Get all peer addresss. */ #define SCTP_GET_LOCAL_ADDRS 109 /* Get all local addresss. */ #define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ #define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ /* SCTP socket option used to read per endpoint association statistics. */ #define SCTP_GET_ASSOC_STATS 112 /* Read only */ /* * 5.2.1 SCTP Initiation Structure (SCTP_INIT) * * This cmsghdr structure provides information for initializing new * SCTP associations with sendmsg(). The SCTP_INITMSG socket option * uses this same data structure. This structure is not used for * recvmsg(). * * cmsg_level cmsg_type cmsg_data[] * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg * */ struct sctp_initmsg { __u16 sinit_num_ostreams; __u16 sinit_max_instreams; __u16 sinit_max_attempts; __u16 sinit_max_init_timeo; }; /* * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * * This cmsghdr structure specifies SCTP options for sendmsg() and * describes SCTP header information about a received message through * recvmsg(). * * cmsg_level cmsg_type cmsg_data[] * ------------ ------------ ---------------------- * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo * */ struct sctp_sndrcvinfo { __u16 sinfo_stream; __u16 sinfo_ssn; __u16 sinfo_flags; __u32 sinfo_ppid; __u32 sinfo_context; __u32 sinfo_timetolive; __u32 sinfo_tsn; __u32 sinfo_cumtsn; sctp_assoc_t sinfo_assoc_id; }; /* * sinfo_flags: 16 bits (unsigned integer) * * This field may contain any of the following flags and is composed of * a bitwise OR of these values. */ 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_SACK_IMMEDIATELY = 8, /* SACK should be sent without delay */ SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */ }; typedef union { __u8 raw; struct sctp_initmsg init; struct sctp_sndrcvinfo sndrcv; } sctp_cmsg_data_t; /* These are cmsg_types. */ typedef enum sctp_cmsg_type { SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ #define SCTP_INIT SCTP_INIT SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ #define SCTP_SNDRCV SCTP_SNDRCV } sctp_cmsg_t; /* * 5.3.1.1 SCTP_ASSOC_CHANGE * * Communication notifications inform the ULP that an SCTP association * has either begun or ended. The identifier for a new association is * provided by this notificaion. The notification information has the * following format: * */ struct sctp_assoc_change { __u16 sac_type; __u16 sac_flags; __u32 sac_length; __u16 sac_state; __u16 sac_error; __u16 sac_outbound_streams; __u16 sac_inbound_streams; sctp_assoc_t sac_assoc_id; __u8 sac_info[0]; }; /* * sac_state: 32 bits (signed integer) * * This field holds one of a number of values that communicate the * event that happened to the association. They include: * * Note: The following state names deviate from the API draft as * the names clash too easily with other kernel symbols. */ enum sctp_sac_state { SCTP_COMM_UP, SCTP_COMM_LOST, SCTP_RESTART, SCTP_SHUTDOWN_COMP, SCTP_CANT_STR_ASSOC, }; /* * 5.3.1.2 SCTP_PEER_ADDR_CHANGE * * When a destination address on a multi-homed peer encounters a change * an interface details event is sent. The information has the * following structure: */ struct sctp_paddr_change { __u16 spc_type; __u16 spc_flags; __u32 spc_length; struct sockaddr_storage spc_aaddr; int spc_state; int spc_error; sctp_assoc_t spc_assoc_id; } __attribute__((packed, aligned(4))); /* * spc_state: 32 bits (signed integer) * * This field holds one of a number of values that communicate the * event that happened to the address. They include: */ enum sctp_spc_state { SCTP_ADDR_AVAILABLE, SCTP_ADDR_UNREACHABLE, SCTP_ADDR_REMOVED, SCTP_ADDR_ADDED, SCTP_ADDR_MADE_PRIM, SCTP_ADDR_CONFIRMED, }; /* * 5.3.1.3 SCTP_REMOTE_ERROR * * A remote peer may send an Operational Error message to its peer. * This message indicates a variety of error conditions on an * association. The entire error TLV as it appears on the wire is * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP * specification [SCTP] and any extensions for a list of possible * error formats. SCTP error TLVs have the format: */ struct sctp_remote_error { __u16 sre_type; __u16 sre_flags; __u32 sre_length; __u16 sre_error; sctp_assoc_t sre_assoc_id; __u8 sre_data[0]; }; /* * 5.3.1.4 SCTP_SEND_FAILED * * If SCTP cannot deliver a message it may return the message as a * notification. */ struct sctp_send_failed { __u16 ssf_type; __u16 ssf_flags; __u32 ssf_length; __u32 ssf_error; struct sctp_sndrcvinfo ssf_info; sctp_assoc_t ssf_assoc_id; __u8 ssf_data[0]; }; /* * ssf_flags: 16 bits (unsigned integer) * * The flag value will take one of the following values * * SCTP_DATA_UNSENT - Indicates that the data was never put on * the wire. * * SCTP_DATA_SENT - Indicates that the data was put on the wire. * Note that this does not necessarily mean that the * data was (or was not) successfully delivered. */ enum sctp_ssf_flags { SCTP_DATA_UNSENT, SCTP_DATA_SENT, }; /* * 5.3.1.5 SCTP_SHUTDOWN_EVENT * * When a peer sends a SHUTDOWN, SCTP delivers this notification to * inform the application that it should cease sending data. */ struct sctp_shutdown_event { __u16 sse_type; __u16 sse_flags; __u32 sse_length; sctp_assoc_t sse_assoc_id; }; /* * 5.3.1.6 SCTP_ADAPTATION_INDICATION * * When a peer sends a Adaptation Layer Indication parameter , SCTP * delivers this notification to inform the application * that of the peers requested adaptation layer. */ struct sctp_adaptation_event { __u16 sai_type; __u16 sai_flags; __u32 sai_length; __u32 sai_adaptation_ind; sctp_assoc_t sai_assoc_id; }; /* * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT * * When a receiver is engaged in a partial delivery of a * message this notification will be used to indicate * various events. */ struct sctp_pdapi_event { __u16 pdapi_type; __u16 pdapi_flags; __u32 pdapi_length; __u32 pdapi_indication; sctp_assoc_t pdapi_assoc_id; }; enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; /* * 5.3.1.8. SCTP_AUTHENTICATION_EVENT * * When a receiver is using authentication this message will provide * notifications regarding new keys being made active as well as errors. */ struct sctp_authkey_event { __u16 auth_type; __u16 auth_flags; __u32 auth_length; __u16 auth_keynumber; __u16 auth_altkeynumber; __u32 auth_indication; sctp_assoc_t auth_assoc_id; }; enum { SCTP_AUTH_NEWKEY = 0, }; struct sctp_sender_dry_event { __u16 sender_dry_type; __u16 sender_dry_flags; __u32 sender_dry_length; sctp_assoc_t sender_dry_assoc_id; }; /* * Described in Section 7.3 * Ancillary Data and Notification Interest Options */ struct sctp_event_subscribe { __u8 sctp_data_io_event; __u8 sctp_association_event; __u8 sctp_address_event; __u8 sctp_send_failure_event; __u8 sctp_peer_error_event; __u8 sctp_shutdown_event; __u8 sctp_partial_delivery_event; __u8 sctp_adaptation_layer_event; __u8 sctp_authentication_event; __u8 sctp_sender_dry_event; }; /* * 5.3.1 SCTP Notification Structure * * The notification structure is defined as the union of all * notification types. * */ union sctp_notification { struct { __u16 sn_type; /* Notification type. */ __u16 sn_flags; __u32 sn_length; } sn_header; struct sctp_assoc_change sn_assoc_change; struct sctp_paddr_change sn_paddr_change; struct sctp_remote_error sn_remote_error; struct sctp_send_failed sn_send_failed; struct sctp_shutdown_event sn_shutdown_event; struct sctp_adaptation_event sn_adaptation_event; struct sctp_pdapi_event sn_pdapi_event; struct sctp_authkey_event sn_authkey_event; struct sctp_sender_dry_event sn_sender_dry_event; }; /* Section 5.3.1 * All standard values for sn_type flags are greater than 2^15. * Values from 2^15 and down are reserved. */ enum sctp_sn_type { SCTP_SN_TYPE_BASE = (1<<15), SCTP_ASSOC_CHANGE, #define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE SCTP_PEER_ADDR_CHANGE, #define SCTP_PEER_ADDR_CHANGE SCTP_PEER_ADDR_CHANGE SCTP_SEND_FAILED, #define SCTP_SEND_FAILED SCTP_SEND_FAILED SCTP_REMOTE_ERROR, #define SCTP_REMOTE_ERROR SCTP_REMOTE_ERROR SCTP_SHUTDOWN_EVENT, #define SCTP_SHUTDOWN_EVENT SCTP_SHUTDOWN_EVENT SCTP_PARTIAL_DELIVERY_EVENT, #define SCTP_PARTIAL_DELIVERY_EVENT SCTP_PARTIAL_DELIVERY_EVENT SCTP_ADAPTATION_INDICATION, #define SCTP_ADAPTATION_INDICATION SCTP_ADAPTATION_INDICATION SCTP_AUTHENTICATION_INDICATION, #define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_INDICATION SCTP_SENDER_DRY_EVENT, #define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT }; /* Notification error codes used to fill up the error fields in some * notifications. * SCTP_PEER_ADDRESS_CHAGE : spc_error * SCTP_ASSOC_CHANGE : sac_error * These names should be potentially included in the draft 04 of the SCTP * sockets API specification. */ typedef enum sctp_sn_error { SCTP_FAILED_THRESHOLD, SCTP_RECEIVED_SACK, SCTP_HEARTBEAT_SUCCESS, SCTP_RESPONSE_TO_USER_REQ, SCTP_INTERNAL_ERROR, SCTP_SHUTDOWN_GUARD_EXPIRES, SCTP_PEER_FAULTY, } sctp_sn_error_t; /* * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) * * 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. */ struct sctp_rtoinfo { sctp_assoc_t srto_assoc_id; __u32 srto_initial; __u32 srto_max; __u32 srto_min; }; /* * 7.1.2 Association Parameters (SCTP_ASSOCINFO) * * This option is used to both examine and set various association and * endpoint parameters. */ struct sctp_assocparams { sctp_assoc_t sasoc_assoc_id; __u16 sasoc_asocmaxrxt; __u16 sasoc_number_peer_destinations; __u32 sasoc_peer_rwnd; __u32 sasoc_local_rwnd; __u32 sasoc_cookie_life; }; /* * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) * * Requests that the peer mark the enclosed address as the association * primary. The enclosed address must be one of the association's * locally bound addresses. The following structure is used to make a * set primary request: */ struct sctp_setpeerprim { sctp_assoc_t sspp_assoc_id; struct sockaddr_storage sspp_addr; } __attribute__((packed, aligned(4))); /* * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) * * Requests that the local SCTP stack use the enclosed peer address as * the association primary. The enclosed address must be one of the * association peer's addresses. The following structure is used to * make a set peer primary request: */ struct sctp_setprim { sctp_assoc_t ssp_assoc_id; struct sockaddr_storage ssp_addr; } __attribute__((packed, aligned(4))); /* For backward compatibility use, define the old name too */ #define sctp_prim sctp_setprim /* * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) * * Requests that the local endpoint set the specified Adaptation Layer * Indication parameter for all future INIT and INIT-ACK exchanges. */ struct sctp_setadaptation { __u32 ssb_adaptation_ind; }; /* * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) * * Applications can enable or disable heartbeats for any peer address * of an association, modify an address's heartbeat interval, force a * heartbeat to be sent immediately, and adjust the address's maximum * number of retransmissions sent before an address is considered * unreachable. The following structure is used to access and modify an * address's parameters: */ enum sctp_spp_flags { SPP_HB_ENABLE = 1<<0, /*Enable heartbeats*/ SPP_HB_DISABLE = 1<<1, /*Disable heartbeats*/ SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE, SPP_HB_DEMAND = 1<<2, /*Send heartbeat immediately*/ SPP_PMTUD_ENABLE = 1<<3, /*Enable PMTU discovery*/ SPP_PMTUD_DISABLE = 1<<4, /*Disable PMTU discovery*/ SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE, SPP_SACKDELAY_ENABLE = 1<<5, /*Enable SACK*/ SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/ SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE, SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */ }; struct sctp_paddrparams { sctp_assoc_t spp_assoc_id; struct sockaddr_storage spp_address; __u32 spp_hbinterval; __u16 spp_pathmaxrxt; __u32 spp_pathmtu; __u32 spp_sackdelay; __u32 spp_flags; } __attribute__((packed, aligned(4))); /* * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) * * This set option adds a chunk type that the user is requesting to be * received only in an authenticated way. Changes to the list of chunks * will only effect future associations on the socket. */ struct sctp_authchunk { __u8 sauth_chunk; }; /* * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) * * This option gets or sets the list of HMAC algorithms that the local * endpoint requires the peer to use. */ enum { SCTP_AUTH_HMAC_ID_SHA1 = 1, SCTP_AUTH_HMAC_ID_SHA256 = 3, }; struct sctp_hmacalgo { __u32 shmac_number_of_idents; __u16 shmac_idents[]; }; /* * 7.1.20. Set a shared key (SCTP_AUTH_KEY) * * This option will set a shared secret key which is used to build an * association shared key. */ struct sctp_authkey { sctp_assoc_t sca_assoc_id; __u16 sca_keynumber; __u16 sca_keylength; __u8 sca_key[]; }; /* * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) * * This option will get or set the active shared key to be used to build * the association shared key. */ struct sctp_authkeyid { sctp_assoc_t scact_assoc_id; __u16 scact_keynumber; }; /* * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) * * This option will effect the way delayed acks are performed. This * option allows you to get or set the delayed ack time, in * milliseconds. It also allows changing the delayed ack frequency. * Changing the frequency to 1 disables the delayed sack algorithm. If * the assoc_id is 0, then this sets or gets the endpoints default * values. If the assoc_id field is non-zero, then the set or get * effects the specified association for the one to many model (the * assoc_id field is ignored by the one to one model). Note that if * sack_delay or sack_freq are 0 when setting this option, then the * current values will remain unchanged. */ struct sctp_sack_info { sctp_assoc_t sack_assoc_id; uint32_t sack_delay; uint32_t sack_freq; }; struct sctp_assoc_value { sctp_assoc_t assoc_id; uint32_t assoc_value; }; /* * 7.2.2 Peer Address Information * * Applications can retrieve information about a specific peer address * of an association, including its reachability state, congestion * window, and retransmission timer values. This information is * read-only. The following structure is used to access this * information: */ struct sctp_paddrinfo { sctp_assoc_t spinfo_assoc_id; struct sockaddr_storage spinfo_address; __s32 spinfo_state; __u32 spinfo_cwnd; __u32 spinfo_srtt; __u32 spinfo_rto; __u32 spinfo_mtu; } __attribute__((packed, aligned(4))); /* Peer addresses's state. */ /* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x] * calls. * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters. * Not yet confirmed by a heartbeat and not available for data * transfers. * ACTIVE : Peer address confirmed, active and available for data transfers. * INACTIVE: Peer address inactive and not available for data transfers. */ enum sctp_spinfo_state { SCTP_INACTIVE, SCTP_PF, SCTP_ACTIVE, SCTP_UNCONFIRMED, SCTP_UNKNOWN = 0xffff }; /* * 7.2.1 Association Status (SCTP_STATUS) * * Applications can retrieve current status information about an * association, including association state, peer receiver window size, * number of unacked data chunks, and number of data chunks pending * receipt. This information is read-only. The following structure is * used to access this information: */ struct sctp_status { sctp_assoc_t sstat_assoc_id; __s32 sstat_state; __u32 sstat_rwnd; __u16 sstat_unackdata; __u16 sstat_penddata; __u16 sstat_instrms; __u16 sstat_outstrms; __u32 sstat_fragmentation_point; struct sctp_paddrinfo sstat_primary; }; /* * 7.2.3. Get the list of chunks the peer requires to be authenticated * (SCTP_PEER_AUTH_CHUNKS) * * This option gets a list of chunks for a specified association that * the peer requires to be received authenticated only. */ struct sctp_authchunks { sctp_assoc_t gauth_assoc_id; __u32 gauth_number_of_chunks; uint8_t gauth_chunks[]; }; /* The broken spelling has been released already, * so don't break anyone, now that it's fixed. */ #define guth_number_of_chunks gauth_number_of_chunks /* Association states. */ enum sctp_sstat_state { SCTP_EMPTY = 0, SCTP_CLOSED = 1, SCTP_COOKIE_WAIT = 2, SCTP_COOKIE_ECHOED = 3, SCTP_ESTABLISHED = 4, SCTP_SHUTDOWN_PENDING = 5, SCTP_SHUTDOWN_SENT = 6, SCTP_SHUTDOWN_RECEIVED = 7, SCTP_SHUTDOWN_ACK_SENT = 8, }; /* * 8.3, 8.5 get all peer/local addresses in an association. * 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. */ struct sctp_getaddrs_old { sctp_assoc_t assoc_id; int addr_num; struct sockaddr *addrs; }; struct sctp_getaddrs { sctp_assoc_t assoc_id; /*input*/ __u32 addr_num; /*output*/ __u8 addrs[0]; /*output, variable size*/ }; /* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves * association stats. All stats are counts except sas_maxrto and * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since * the last call. Will return 0 when did not change since last call */ struct sctp_assoc_stats { sctp_assoc_t sas_assoc_id; /* Input */ /* Transport of the observed max RTO spike */ struct sockaddr_storage sas_obs_rto_ipaddr; __u64 sas_maxrto; /* Maximum Observed RTO for period */ __u64 sas_isacks; /* SACKs received */ __u64 sas_osacks; /* SACKs sent */ __u64 sas_opackets; /* Packets sent */ __u64 sas_ipackets; /* Packets received */ __u64 sas_rtxchunks; /* Retransmitted Chunks */ __u64 sas_outofseqtsns;/* TSN received > next expected */ __u64 sas_idupchunks; /* Dups received (ordered+unordered) */ __u64 sas_gapcnt; /* Gap Acknowledgements Received */ __u64 sas_ouodchunks; /* Unordered data chunks sent */ __u64 sas_iuodchunks; /* Unordered data chunks received */ __u64 sas_oodchunks; /* Ordered data chunks sent */ __u64 sas_iodchunks; /* Ordered data chunks received */ __u64 sas_octrlchunks; /* Control chunks sent */ __u64 sas_ictrlchunks; /* Control chunks received */ }; /* These are bit fields for msghdr->msg_flags. See section 5.1. */ /* On user space Linux, these live in as an enum. */ enum sctp_msg_flags { MSG_NOTIFICATION = 0x8000, #define MSG_NOTIFICATION MSG_NOTIFICATION }; /* * 8.1 sctp_bindx() * * The flags parameter is formed from the bitwise OR of zero or more of the * following currently defined flags: */ #define SCTP_BINDX_ADD_ADDR 0x01 #define SCTP_BINDX_REM_ADDR 0x02 /* This is the structure that is passed as an argument(optval) to * getsockopt(SCTP_SOCKOPT_PEELOFF). */ typedef struct { sctp_assoc_t associd; int sd; } sctp_peeloff_arg_t; int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags); int sctp_connectx(int sd, struct sockaddr *addrs, int addrcnt, sctp_assoc_t *id); int sctp_peeloff(int sd, sctp_assoc_t assoc_id); /* Prototype for the library function sctp_opt_info defined in * API 7. Socket Options. */ int sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size); /* Get all peer address on a socket. This is a new SCTP API * described in the section 8.3 of the Sockets API Extensions for SCTP. * This is implemented using the getsockopt() interface. */ int sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs); /* Frees all resources allocated by sctp_getpaddrs(). This is a new SCTP API * described in the section 8.4 of the Sockets API Extensions for SCTP. */ int sctp_freepaddrs(struct sockaddr *addrs); /* Get all locally bound address on a socket. This is a new SCTP API * described in the section 8.5 of the Sockets API Extensions for SCTP. * This is implemented using the getsockopt() interface. */ int sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs); /* Frees all resources allocated by sctp_getladdrs(). This is a new SCTP API * described in the section 8.6 of the Sockets API Extensions for SCTP. */ int sctp_freeladdrs(struct sockaddr *addrs); /* This library function assists the user with the advanced features * of SCTP. This is a new SCTP API described in the section 8.7 of the * Sockets API Extensions for SCTP. This is implemented using the * sendmsg() interface. */ 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); /* This library function assist the user with sending a message without * dealing directly with the CMSG header. */ int sctp_send(int s, const void *msg, size_t len, const struct sctp_sndrcvinfo *sinfo, int flags); /* This library function assists the user with the advanced features * of SCTP. This is a new SCTP API described in the section 8.8 of the * Sockets API Extensions for SCTP. This is implemented using the * recvmsg() interface. */ int sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from, socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags); /* Return the address length for an address family. */ int sctp_getaddrlen(sa_family_t family); __END_DECLS #endif /* __linux_sctp_h__ */ lksctp-tools-1.0.16+dfsg.orig/src/include/netinet/Makefile.am0000644000175000017500000000041312300634451023611 0ustar michaelmichael include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules libcnetinetdir = $(includedir)/netinet ## FIXME: Your stuff here # Supposing this is part of the development package, header for our # API. include_HEADERS = libcnetinet_HEADERS = sctp.h lksctp-tools-1.0.16+dfsg.orig/src/include/Makefile.am0000644000175000017500000000013512300634451022144 0ustar michaelmichael include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules SUBDIRS = netinet lksctp-tools-1.0.16+dfsg.orig/src/lib/0000755000175000017500000000000012300634451017234 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/lib/recvmsg.c0000644000175000017500000000557012300634451021055 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * sctp_recvmsg.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in * * Copyright (c) 2003 International Business Machines, Corp. * * Written or modified by: * Ryan Layer * * An implementation may provide a library function (or possibly system * call) to assist the user with the advanced features of SCTP. Note * that in order for the sctp_sndrcvinfo structure to be filled in by * sctp_recvmsg() the caller must enable the sctp_data_io_events with * the SCTP_EVENTS option. * * sctp_recvmsg(). Its syntax is, * * int sctp_recvmsg(int s, * void *msg, * size_t len, * struct sockaddr *from, * socklen_t *fromlen, * struct sctp_sndrcvinfo *sinfo, * int *msg_flags) * * * s - is the socket descriptor * msg - is a message buffer to be filled. * len - is the length of the message buffer. * from - is a pointer to a address to be filled with * the sender of this messages address. * fromlen - is the from length. * sinfo - A pointer to a sctp_sndrcvinfo structure * to be filled upon receipt of the message. * msg_flags - A pointer to a integer to be filled with * any message flags (e.g. MSG_NOTIFICATION). */ #include #include #include /* struct sockaddr_storage, setsockopt() */ #include int sctp_recvmsg(int s, void *msg, size_t len, struct sockaddr *from, socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags) { int error; struct iovec iov; struct msghdr inmsg; char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg = NULL; memset(&inmsg, 0, sizeof (inmsg)); iov.iov_base = msg; iov.iov_len = len; inmsg.msg_name = from; inmsg.msg_namelen = fromlen ? *fromlen : 0; inmsg.msg_iov = &iov; inmsg.msg_iovlen = 1; inmsg.msg_control = incmsg; inmsg.msg_controllen = sizeof(incmsg); error = recvmsg(s, &inmsg, msg_flags ? *msg_flags : 0); if (error < 0) return error; if (fromlen) *fromlen = inmsg.msg_namelen; if (msg_flags) *msg_flags = inmsg.msg_flags; if (!sinfo) return error; for (cmsg = CMSG_FIRSTHDR(&inmsg); cmsg != NULL; cmsg = CMSG_NXTHDR(&inmsg, cmsg)){ if ((IPPROTO_SCTP == cmsg->cmsg_level) && (SCTP_SNDRCV == cmsg->cmsg_type)) break; } /* Copy sinfo. */ if (cmsg) memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo)); return (error); } lksctp-tools-1.0.16+dfsg.orig/src/lib/connectx.c0000644000175000017500000001136412300634451021226 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * connectx.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt. * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in */ #include /* struct sockaddr_storage, setsockopt() */ #include #include /* SCTP_SOCKOPT_CONNECTX_* */ #include #include #include #include /* Support the sctp_connectx() interface. * * See Sockets API Extensions for SCTP. Section 8.1. * * Instead of implementing through a socket call in sys_socketcall(), * tunnel the request through setsockopt(). */ static int __connectx_addrsize(const struct sockaddr *addrs, const int addrcnt) { const void *addrbuf; const struct sockaddr *sa_addr; int addrs_size = 0; int i; addrbuf = addrs; for (i = 0; i < addrcnt; i++) { sa_addr = (const struct sockaddr *)addrbuf; switch (sa_addr->sa_family) { case AF_INET: addrs_size += sizeof(struct sockaddr_in); addrbuf += sizeof(struct sockaddr_in); break; case AF_INET6: addrs_size += sizeof(struct sockaddr_in6); addrbuf += sizeof(struct sockaddr_in6); break; default: errno = EINVAL; return -1; } } return addrs_size; } int __sctp_connectx(int fd, struct sockaddr *addrs, int addrcnt) { socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt); if (addrs_size < 0) return addrs_size; return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, addrs, addrs_size); } extern int sctp_connectx_orig (int) __attribute ((alias ("__sctp_connectx"))); static int __connectx(int fd, struct sockaddr *addrs, socklen_t addrs_size, sctp_assoc_t *id) { int status; if (id) *id = 0; status = setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX, addrs, addrs_size); /* Normalize status and set association id */ if (status > 0) { if (id) *id = status; return 0; } /* The error is something other then "Option not supported" */ if (status < 0 && errno != ENOPROTOOPT) return status; /* At this point, if the application wanted the id, we can't * really provide it, so we can return ENOPROTOOPT. */ if (id) { errno = ENOPROTOOPT; return -1; } /* Finally, try the old API */ return setsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX_OLD, addrs, addrs_size); } int sctp_connectx2(int fd, struct sockaddr *addrs, int addrcnt, sctp_assoc_t *id) { socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt); if (addrs_size < 0) return addrs_size; return __connectx(fd, addrs, addrs_size, id); } int sctp_connectx3(int fd, struct sockaddr *addrs, int addrcnt, sctp_assoc_t *id) { socklen_t addrs_size = __connectx_addrsize(addrs, addrcnt); int status; struct sctp_getaddrs_old param; socklen_t opt_len = sizeof(param); if (addrs_size < 0) return addrs_size; /* First try the new socket api * Because the id is returned in the option buffer we have prepend * 32bit to it for the returned association id */ param.assoc_id = 0; param.addr_num = addrs_size; param.addrs = addrs; status = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_CONNECTX3, ¶m, &opt_len); if (status == 0 || errno == EINPROGRESS) { /* Succeeded immediately, or initiated on non-blocking * socket. */ if (id) *id = param.assoc_id; } if (errno != ENOPROTOOPT) { /* No point in trying the fallbacks*/ return status; } /* The first incarnation of updated connectx api didn't work for * non-blocking sockets. So if the application wants the association * id and the socket is non-blocking, we can't really do anything. */ if (id) { /* Program wants the association-id returned. We can only do * that if the socket is blocking */ status = fcntl(fd, F_GETFL); if (status < 0) return status; if (status & O_NONBLOCK) { /* Socket is non-blocking. Fail */ errno = ENOPROTOOPT; return -1; } } return __connectx(fd, addrs, addrs_size, id); } #define __SYMPFX(pfx, sym) #pfx sym #define _SYMPFX(pfx, sym) __SYMPFX(pfx, sym) #define SYMPFX(sym) _SYMPFX(__USER_LABEL_PREFIX__, #sym) #define SYMVER(name, name2) __asm__(".symver " SYMPFX(name) "," SYMPFX(name2)) SYMVER(__sctp_connectx, sctp_connectx@); SYMVER(sctp_connectx_orig, sctp_connectx@VERS_1); SYMVER(sctp_connectx2, sctp_connectx@VERS_2); SYMVER(sctp_connectx3, sctp_connectx@@VERS_3); lksctp-tools-1.0.16+dfsg.orig/src/lib/sendmsg.c0000644000175000017500000000600112300634451021035 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * sendmsg.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in * * Copyright (c) 2003 Intel Corp. * * Written or modified by: * Ardelle Fan */ #include #include /* struct sockaddr_storage, setsockopt() */ #include /* This library function assists the user with the advanced features * of SCTP. This is a new SCTP API described in the section 8.7 of the * Sockets API Extensions for SCTP. This is implemented using the * sendmsg() interface. */ 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) { struct msghdr outmsg; struct iovec iov; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; struct cmsghdr *cmsg; struct sctp_sndrcvinfo *sinfo; outmsg.msg_name = to; outmsg.msg_namelen = tolen; outmsg.msg_iov = &iov; iov.iov_base = (void *)msg; iov.iov_len = len; outmsg.msg_iovlen = 1; outmsg.msg_control = outcmsg; outmsg.msg_controllen = sizeof(outcmsg); outmsg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmsg); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmsg.msg_controllen = cmsg->cmsg_len; sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo)); sinfo->sinfo_ppid = ppid; sinfo->sinfo_flags = flags; sinfo->sinfo_stream = stream_no; sinfo->sinfo_timetolive = timetolive; sinfo->sinfo_context = context; return sendmsg(s, &outmsg, 0); } /* This library function assist the user with sending a message without * dealing directly with the CMSG header. */ int sctp_send(int s, const void *msg, size_t len, const struct sctp_sndrcvinfo *sinfo, int flags) { struct msghdr outmsg; struct iovec iov; char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; outmsg.msg_name = NULL; outmsg.msg_namelen = 0; outmsg.msg_iov = &iov; iov.iov_base = (void *)msg; iov.iov_len = len; outmsg.msg_iovlen = 1; outmsg.msg_controllen = 0; if (sinfo) { struct cmsghdr *cmsg; outmsg.msg_control = outcmsg; outmsg.msg_controllen = sizeof(outcmsg); outmsg.msg_flags = 0; cmsg = CMSG_FIRSTHDR(&outmsg); cmsg->cmsg_level = IPPROTO_SCTP; cmsg->cmsg_type = SCTP_SNDRCV; cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); outmsg.msg_controllen = cmsg->cmsg_len; memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo)); } return sendmsg(s, &outmsg, flags); } lksctp-tools-1.0.16+dfsg.orig/src/lib/addrs.c0000644000175000017500000000763312300634451020506 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * addrs.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in * Sridhar Samudrala * Ivan Skytte Jørgensen */ #include #include #include #include #include /* * Common getsockopt() layer * If the NEW getsockopt() API fails this function will fall back to using * the old API */ static int sctp_getaddrs(int sd, sctp_assoc_t id, int optname_new, struct sockaddr **addrs) { int cnt, err; socklen_t len; size_t bufsize = 4096; /*enough for most cases*/ struct sctp_getaddrs *getaddrs = (struct sctp_getaddrs*)malloc(bufsize); if(!getaddrs) return -1; for(;;) { char *new_buf; len = bufsize; getaddrs->assoc_id = id; err = getsockopt(sd, SOL_SCTP, optname_new, getaddrs, &len); if (err == 0) { /*got it*/ break; } if (errno != ENOMEM ) { /*unknown error*/ free(getaddrs); return -1; } /*expand buffer*/ if (bufsize > 128*1024) { /*this is getting ridiculous*/ free(getaddrs); errno = ENOBUFS; return -1; } new_buf = realloc(getaddrs, bufsize+4096); if (!new_buf) { free(getaddrs); return -1; } bufsize += 4096; getaddrs = (struct sctp_getaddrs*)new_buf; } /* we skip traversing the list, allocating a new buffer etc. and enjoy * a simple hack*/ cnt = getaddrs->addr_num; memmove(getaddrs, getaddrs + 1, len); *addrs = (struct sockaddr*)getaddrs; return cnt; } /* sctp_getaddrs() */ /* Get all peer address on a socket. This is a new SCTP API * described in the section 8.3 of the Sockets API Extensions for SCTP. * This is implemented using the getsockopt() interface. */ int sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **addrs) { return sctp_getaddrs(sd, id, SCTP_GET_PEER_ADDRS, addrs); } /* sctp_getpaddrs() */ /* Frees all resources allocated by sctp_getpaddrs(). This is a new SCTP API * described in the section 8.4 of the Sockets API Extensions for SCTP. */ int sctp_freepaddrs(struct sockaddr *addrs) { free(addrs); return 0; } /* sctp_freepaddrs() */ /* Get all locally bound address on a socket. This is a new SCTP API * described in the section 8.5 of the Sockets API Extensions for SCTP. * This is implemented using the getsockopt() interface. */ int sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **addrs) { return sctp_getaddrs(sd, id, SCTP_GET_LOCAL_ADDRS, addrs); } /* sctp_getladdrs() */ /* Frees all resources allocated by sctp_getladdrs(). This is a new SCTP API * described in the section 8.6 of the Sockets API Extensions for SCTP. */ int sctp_freeladdrs(struct sockaddr *addrs) { free(addrs); return 0; } /* sctp_freeladdrs() */ int sctp_getaddrlen(sa_family_t family) { /* We could call into the kernel to see what it thinks the size should * be, but hardcoding the address families here is: (a) faster, * (b) easier, and (c) probably good enough for forseeable future. */ switch(family) { case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); default: /* Currently there is no defined error handling in * draft-ietf-tsvwg-sctpsocket-13.txt. * -1 might cause the application to overwrite buffer * or misinterpret data. 0 is more likely to cause * an endless loop. */ return 0; } } lksctp-tools-1.0.16+dfsg.orig/src/lib/Versions.map0000644000175000017500000000050512300634451021543 0ustar michaelmichaelVERS_1 { global: sctp_getpaddrs; sctp_freepaddrs; sctp_getladdrs; sctp_freeladdrs; sctp_getaddrlen; sctp_bindx; sctp_connectx; sctp_opt_info; sctp_peeloff; sctp_recvmsg; sctp_sendmsg; sctp_send; local: *; }; VERS_2 { global: sctp_connectx; } VERS_1; VERS_3 { global: sctp_connectx; } VERS_2; lksctp-tools-1.0.16+dfsg.orig/src/lib/peeloff.c0000644000175000017500000000252412300634451021023 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * peeloff.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in */ #include /* struct sockaddr_storage, setsockopt() */ #include /* SCTP_SOCKOPT_BINDX_* */ #include /* Branch off an association into a seperate socket. This is a new SCTP API * described in the section 8.2 of the Sockets API Extensions for SCTP. * This is implemented using the getsockopt() interface. */ int sctp_peeloff(int fd, sctp_assoc_t associd) { sctp_peeloff_arg_t peeloff; socklen_t peeloff_size = sizeof(peeloff); int err; peeloff.associd = associd; peeloff.sd = 0; err = getsockopt(fd, SOL_SCTP, SCTP_SOCKOPT_PEELOFF, &peeloff, &peeloff_size); if (err < 0) { return err; } return peeloff.sd; } /* sctp_peeloff() */ lksctp-tools-1.0.16+dfsg.orig/src/lib/bindx.c0000644000175000017500000000407412300634451020511 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * bindx.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code is to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in * Daisy Chang * Inaky Perez-Gonzalez * Sridhar Samudrala */ #include /* struct sockaddr_storage, setsockopt() */ #include #include /* SCTP_SOCKOPT_BINDX_* */ #include /* Support the sctp_bindx() interface. * * See Sockets API Extensions for SCTP. Section 8.1. * * Instead of implementing through a socket call in sys_socketcall(), * tunnel the request through setsockopt(). */ int sctp_bindx(int fd, struct sockaddr *addrs, int addrcnt, int flags) { int setsock_option = 0; void *addrbuf; struct sockaddr *sa_addr; socklen_t addrs_size = 0; int i; switch (flags) { case SCTP_BINDX_ADD_ADDR: setsock_option = SCTP_SOCKOPT_BINDX_ADD; break; case SCTP_BINDX_REM_ADDR: setsock_option = SCTP_SOCKOPT_BINDX_REM; break; default: errno = EINVAL; return -1; } addrbuf = addrs; for (i = 0; i < addrcnt; i++) { sa_addr = (struct sockaddr *)addrbuf; switch (sa_addr->sa_family) { case AF_INET: addrs_size += sizeof(struct sockaddr_in); addrbuf += sizeof(struct sockaddr_in); break; case AF_INET6: addrs_size += sizeof(struct sockaddr_in6); addrbuf += sizeof(struct sockaddr_in6); break; default: errno = EINVAL; return -1; } } return setsockopt(fd, SOL_SCTP, setsock_option, addrs, addrs_size); } lksctp-tools-1.0.16+dfsg.orig/src/lib/Makefile.am0000644000175000017500000000067712300634451021302 0ustar michaelmichael# Include these two in all the Makefile.am's!!! include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules include $(top_srcdir)/Makefile.dirs # General compilation flags AM_CPPFLAGS = -I$(top_srcdir)/src/include lib_LTLIBRARIES = libsctp.la libsctp_la_SOURCES = bindx.c connectx.c peeloff.c opt_info.c addrs.c sendmsg.c recvmsg.c Versions.map libsctp_la_LDFLAGS = -version-info 1:16:0 -Wl,--version-script=$(srcdir)/Versions.map lksctp-tools-1.0.16+dfsg.orig/src/lib/opt_info.c0000644000175000017500000000345412300634451021223 0ustar michaelmichael/* SCTP kernel Implementation: User API extensions. * * opt_info.c * * Distributed under the terms of the LGPL v2.1 as described in * http://www.gnu.org/copyleft/lesser.txt * * This file is part of the user library that offers support for the * SCTP kernel Implementation. The main purpose of this * code if to provide the SCTP Socket API mappings for user * application to interface with the SCTP in kernel. * * This implementation is based on the Socket API Extensions for SCTP * defined in */ #include /* struct sockaddr_storage, setsockopt() */ #include /* SCTP_SOCKOPT_BINDX_* */ #include /* Support the sctp_opt_info() interface. * * See Sockets API Extensions for SCTP. Section 7. * * Pass sctp option information pass both in to and out of the SCTP stack. * This is a new SCTP API described in the section 7 of the Sockets API * Extensions for SCTP. This is implemented using the getsockopt() interface. */ int sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size) { switch (opt) { case SCTP_RTOINFO: case SCTP_ASSOCINFO: case SCTP_INITMSG: case SCTP_NODELAY: case SCTP_AUTOCLOSE: case SCTP_PRIMARY_ADDR: case SCTP_DISABLE_FRAGMENTS: case SCTP_PEER_ADDR_PARAMS: case SCTP_DEFAULT_SEND_PARAM: case SCTP_EVENTS: case SCTP_I_WANT_MAPPED_V4_ADDR: case SCTP_MAXSEG: case SCTP_STATUS: case SCTP_GET_PEER_ADDR_INFO: case SCTP_AUTH_ACTIVE_KEY: case SCTP_PEER_AUTH_CHUNKS: case SCTP_LOCAL_AUTH_CHUNKS: *(sctp_assoc_t *)arg = id; return getsockopt(sd, IPPROTO_SCTP, opt, arg, size); default: return ENOTSUP; } } /* sctp_opt_info() */ lksctp-tools-1.0.16+dfsg.orig/src/Makefile.am0000644000175000017500000000020112300634451020513 0ustar michaelmichaelinclude $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules SUBDIRS = apps func_tests include lib testlib withsctp lksctp-tools-1.0.16+dfsg.orig/src/testlib/0000755000175000017500000000000012300634451020134 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/src/testlib/Makefile.am0000644000175000017500000000052212300634451022167 0ustar michaelmichael# Include these two in all the Makefile.am's!!! include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules include $(top_srcdir)/Makefile.dirs # General compilation flags AM_CPPFLAGS = -I$(top_srcdir)/src/include noinst_LTLIBRARIES = libsctputil.la libsctputil_la_SOURCES = sctputil.c sctputil.h libsctputil_la_LDFLAGS = lksctp-tools-1.0.16+dfsg.orig/src/testlib/sctputil.c0000644000175000017500000002661212300634451022156 0ustar michaelmichael/* SCTP kernel Implementation * (C) Copyright IBM Corp. 2001, 2003 * Copyright (C) 1999 Cisco * Copyright (C) 1999-2000 Motorola # Copyright (C) 2001 Nokia * Copyright (C) 2001 La Monte H.P. Yarroll * * 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 * * 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: * La Monte H.P. Yarroll * Narasimha Budihal * Karl Knutson * Jon Grimm * Daisy Chang * Sridhar Samudrala */ #include #include #include #include #include #include #include #include #include #include #include /* This function prints the cmsg data. */ void test_print_cmsg(sctp_cmsg_t type, sctp_cmsg_data_t *data) { switch(type) { case SCTP_INIT: printf("INIT\n"); printf(" sinit_num_ostreams %d\n", data->init.sinit_num_ostreams); printf(" sinit_max_instreams %d\n", data->init.sinit_max_instreams); printf(" sinit_max_attempts %d\n", data->init.sinit_max_attempts); printf(" sinit_max_init_timeo %d\n", data->init.sinit_max_init_timeo); break; case SCTP_SNDRCV: printf("SNDRCV\n"); printf(" sinfo_stream %u\n", data->sndrcv.sinfo_stream); printf(" sinfo_ssn %u\n", data->sndrcv.sinfo_ssn); printf(" sinfo_flags 0x%x\n", data->sndrcv.sinfo_flags); printf(" sinfo_ppid %u\n", data->sndrcv.sinfo_ppid); printf(" sinfo_context %x\n", data->sndrcv.sinfo_context); printf(" sinfo_tsn %u\n", data->sndrcv.sinfo_tsn); printf(" sinfo_cumtsn %u\n", data->sndrcv.sinfo_cumtsn); printf(" sinfo_assoc_id %u\n", data->sndrcv.sinfo_assoc_id); break; default: printf("UNKNOWN CMSG: %d\n", type); break; } } /* This function prints the message. */ void test_print_message(int sk, struct msghdr *msg, size_t msg_len) { sctp_cmsg_data_t *data; struct cmsghdr *cmsg; int i; int done = 0; char save; union sctp_notification *sn; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { data = (sctp_cmsg_data_t *)CMSG_DATA(cmsg); test_print_cmsg(cmsg->cmsg_type, data); } if (!(MSG_NOTIFICATION & msg->msg_flags)) { int index = 0; /* Make sure that everything is printable and that we * are NUL terminated... */ printf("DATA(%d): ", msg_len); while ( msg_len > 0 ) { char *text; int len; text = msg->msg_iov[index].iov_base; len = msg->msg_iov[index].iov_len; save = text[msg_len-1]; if ( len > msg_len ) { text[(len = msg_len) - 1] = '\0'; } if ( (msg_len -= len) > 0 ) { index++; } for (i = 0; i < len - 1; ++i) { if (!isprint(text[i])) text[i] = '.'; } printf("%s", text); text[msg_len-1] = save; if ( (done = !strcmp(text, "exit")) ) { break; } } } else { printf("NOTIFICATION: "); sn = (union sctp_notification *)msg->msg_iov[0].iov_base; switch (sn->sn_header.sn_type) { case SCTP_ASSOC_CHANGE: switch (sn->sn_assoc_change.sac_state) { case SCTP_COMM_UP: printf("ASSOC_CHANGE - COMM_UP"); break; case SCTP_COMM_LOST: printf("ASSOC_CHANGE - COMM_LOST"); break; case SCTP_RESTART: printf("ASSOC_CHANGE - RESTART"); break; case SCTP_SHUTDOWN_COMP: printf("ASSOC_CHANGE - SHUTDOWN_COMP"); break; case SCTP_CANT_STR_ASSOC: printf("ASSOC_CHANGE - CANT_STR_ASSOC"); break; default: printf("ASSOC_CHANGE - UNEXPECTED(%d)", sn->sn_assoc_change.sac_state); break; } break; default: printf("%d", sn->sn_header.sn_type); break; } } printf("\n"); } /* Check if a buf/msg_flags matches a notification, its type, and possibly an * additional field in the corresponding notification structure. */ void test_check_buf_notification(void *buf, int datalen, int msg_flags, int expected_datalen, uint16_t expected_sn_type, uint32_t expected_additional) { union sctp_notification *sn; if (!(msg_flags & MSG_NOTIFICATION)) tst_brkm(TBROK, tst_exit, "Got a datamsg, expecting " "notification"); if (expected_datalen <= 0) return; if (datalen != expected_datalen) tst_brkm(TBROK, tst_exit, "Got a notification of unexpected " "length:%d, expected length:%d", datalen, expected_datalen); sn = (union sctp_notification *)buf; if (sn->sn_header.sn_type != expected_sn_type) tst_brkm(TBROK, tst_exit, "Unexpected notification:%d" "expected:%d", sn->sn_header.sn_type, expected_sn_type); switch(sn->sn_header.sn_type){ case SCTP_ASSOC_CHANGE: if (sn->sn_assoc_change.sac_state != expected_additional) tst_brkm(TBROK, tst_exit, "Unexpected sac_state:%d " "expected:%d", sn->sn_assoc_change.sac_state, expected_additional); break; default: break; } } /* Check if a message matches a notification, its type, and possibly an * additional field in the corresponding notification structure. */ void test_check_msg_notification(struct msghdr *msg, int datalen, int expected_datalen, uint16_t expected_sn_type, uint32_t expected_additional) { test_check_buf_notification(msg->msg_iov[0].iov_base, datalen, msg->msg_flags, expected_datalen, expected_sn_type, expected_additional); } /* Check if a buf/msg_flags/sinfo corresponds to data, its length, msg_flags, * stream and ppid. */ void test_check_buf_data(void *buf, int datalen, int msg_flags, struct sctp_sndrcvinfo *sinfo, int expected_datalen, int expected_msg_flags, uint16_t expected_stream, uint32_t expected_ppid) { if (msg_flags & MSG_NOTIFICATION) tst_brkm(TBROK, tst_exit, "Got a notification, expecting a" "datamsg"); if (expected_datalen <= 0) return; if (datalen != expected_datalen) tst_brkm(TBROK, tst_exit, "Got a datamsg of unexpected " "length:%d, expected length:%d", datalen, expected_datalen); if ((msg_flags & ~0x80000000) != expected_msg_flags) tst_brkm(TBROK, tst_exit, "Unexpected msg_flags:0x%x " "expecting:0x%x", msg_flags, expected_msg_flags); if ((0 == expected_stream) && (0 == expected_ppid)) return; if (!sinfo) tst_brkm(TBROK, tst_exit, "Null sinfo, but expected " "stream:%d expected ppid:%d", expected_stream, expected_ppid); if (sinfo->sinfo_stream != expected_stream) tst_brkm(TBROK, tst_exit, "stream mismatch: expected:%x " "got:%x", expected_stream, sinfo->sinfo_stream); if (sinfo->sinfo_ppid != expected_ppid) tst_brkm(TBROK, tst_exit, "ppid mismatch: expected:%x " "got:%x\n", expected_ppid, sinfo->sinfo_ppid); } /* Check if a message corresponds to data, its length, msg_flags, stream and * ppid. */ void test_check_msg_data(struct msghdr *msg, int datalen, int expected_datalen, int expected_msg_flags, uint16_t expected_stream, uint32_t expected_ppid) { struct cmsghdr *cmsg = NULL; struct sctp_sndrcvinfo *sinfo = NULL; /* Receive auxiliary data in msgh. */ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)){ if (IPPROTO_SCTP == cmsg->cmsg_level && SCTP_SNDRCV == cmsg->cmsg_type) break; } /* for( all cmsgs) */ if ((!cmsg) || (cmsg->cmsg_len < CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))) sinfo = NULL; else sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); test_check_buf_data(msg->msg_iov[0].iov_base, datalen, msg->msg_flags, sinfo, expected_datalen, expected_msg_flags, expected_stream, expected_ppid); } /* Allocate a buffer of requested len and fill in with data. */ void * test_build_msg(int len) { int i = len - 1; int n; unsigned char msg[] = "012345678901234567890123456789012345678901234567890"; char *msg_buf, *p; msg_buf = (char *)malloc(len); if (!msg_buf) tst_brkm(TBROK, tst_exit, "malloc failed"); p = msg_buf; do { n = ((i > 50)?50:i); memcpy(p, msg, ((i > 50)?50:i)); p += n; i -= n; } while (i > 0); msg_buf[len-1] = '\0'; return(msg_buf); } /* Enable ASSOC_CHANGE and SNDRCVINFO notifications. */ void test_enable_assoc_change(int fd) { struct sctp_event_subscribe subscribe; memset(&subscribe, 0, sizeof(subscribe)); subscribe.sctp_data_io_event = 1; subscribe.sctp_association_event = 1; test_setsockopt(fd, SCTP_EVENTS, (char *)&subscribe, sizeof(subscribe)); } static int cmp_addr(sockaddr_storage_t *addr1, sockaddr_storage_t *addr2) { if (addr1->sa.sa_family != addr2->sa.sa_family) return 0; switch (addr1->sa.sa_family) { case AF_INET6: if (addr1->v6.sin6_port != addr2->v6.sin6_port) return -1; return memcmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr, sizeof(addr1->v6.sin6_addr)); case AF_INET: if (addr1->v4.sin_port != addr2->v4.sin_port) return 0; return memcmp(&addr1->v4.sin_addr, &addr2->v4.sin_addr, sizeof(addr1->v4.sin_addr)); default: tst_brkm(TBROK, tst_exit, "invalid address type %d", addr1->sa.sa_family); return -1; } } /* Test peer addresses for association. */ int test_peer_addr(int sk, sctp_assoc_t asoc, sockaddr_storage_t *peers, int count) { struct sockaddr *addrs; int error, i, j; struct sockaddr *sa_addr; socklen_t addrs_size = 0; void *addrbuf; char *found = (char *) malloc(count); memset(found, 0, count); error = sctp_getpaddrs(sk, asoc, &addrs); if (-1 == error) { tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno)); return error; } if (error != count) { sctp_freepaddrs(addrs); tst_brkm(TBROK, tst_exit, "peer count %d mismatch, expected %d", error, count); } addrbuf = addrs; for (i = 0; i < count; i++) { sa_addr = (struct sockaddr *)addrbuf; switch (sa_addr->sa_family) { case AF_INET: addrs_size += sizeof(struct sockaddr_in); addrbuf += sizeof(struct sockaddr_in); break; case AF_INET6: addrs_size += sizeof(struct sockaddr_in6); addrbuf += sizeof(struct sockaddr_in6); break; default: errno = EINVAL; sctp_freepaddrs(addrs); tst_brkm(TBROK, tst_exit, "sctp_getpaddrs: %s", strerror(errno)); return -1; } for (j = 0; j < count; j++) { if (cmp_addr((sockaddr_storage_t *)sa_addr, &peers[j]) == 0) { found[j] = 1; } } } for (j = 0; j < count; j++) { if (found[j] == 0) { tst_brkm(TBROK, tst_exit, "peer address %d not found", j); } } sctp_freepaddrs(addrs); return 0; } lksctp-tools-1.0.16+dfsg.orig/src/testlib/sctputil.h0000644000175000017500000002251312300634451022157 0ustar michaelmichael/* 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. * Copyright (c) 2001 La Monte H.P. Yarroll * * 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 * * 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: * La Monte H.P. Yarroll * Karl Knutson * Randall Stewart * Ken Morneau * Qiaobing Xie * Daisy Chang * Jon Grimm * Sridhar Samudrala * Hui Huang */ #ifndef __sctputil_h__ #define __sctputil_h__ #ifdef LTP #include #include #endif #include typedef union { struct sockaddr_in v4; struct sockaddr_in6 v6; struct sockaddr sa; } sockaddr_storage_t; #define REALLY_BIG 65536 /* Literal defines. */ #ifdef PROT_SOCK #define SCTP_TESTPORT_1 PROT_SOCK #else #define SCTP_TESTPORT_1 1024 #endif #define SCTP_TESTPORT_2 (SCTP_TESTPORT_1+1) #define SCTP_IP_BCAST htonl(0xffffffff) #define SCTP_IP_LOOPBACK htonl(0x7f000001) /* These are stolen from . */ #define SCTP_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } #define SCTP_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } /* Display an IPv4 address in readable format. */ #define NIPQUAD(addr) \ ((unsigned char *)&addr)[0], \ ((unsigned char *)&addr)[1], \ ((unsigned char *)&addr)[2], \ ((unsigned char *)&addr)[3] /* Display an IPv6 address in readable format. */ #define NIP6(addr) \ ntohs((addr).s6_addr16[0]), \ ntohs((addr).s6_addr16[1]), \ ntohs((addr).s6_addr16[2]), \ ntohs((addr).s6_addr16[3]), \ ntohs((addr).s6_addr16[4]), \ ntohs((addr).s6_addr16[5]), \ ntohs((addr).s6_addr16[6]), \ ntohs((addr).s6_addr16[7]) #define DUMP_CORE { \ char *diediedie = 0; \ printf("DUMP_CORE %s: %d\n", __FILE__, __LINE__);\ *diediedie = 0; \ } #ifndef LTP enum { TPASS, TINFO, }; extern char *TCID; extern int TST_TOTAL; extern int TST_CNT; #define tst_brkm(a1, a2, whatever...) \ { \ printf("%s %2d BROK : ", TCID, ++TST_CNT); \ printf(whatever); \ printf("\n"); \ DUMP_CORE \ } #define tst_resm(a1, whatever...) \ { \ printf("%s %2d %s : ", TCID, \ (a1 == TPASS)?++TST_CNT:0, \ (a1 == TPASS)?"PASS":"INFO"); \ printf(whatever); \ printf("\n"); \ } #endif static inline int test_socket(int domain, int type, int protocol) { int sk = socket(domain, type, protocol); if (-1 == sk) tst_brkm(TBROK, tst_exit, "socket: %s", strerror(errno)); return sk; } static inline int test_bind(int sk, struct sockaddr *addr, socklen_t addrlen) { int error = bind(sk, addr, addrlen); if (-1 == error) tst_brkm(TBROK, tst_exit, "bind: %s", strerror(errno)); return error; } static inline int test_bindx_add(int sk, struct sockaddr *addr, int count) { int error = sctp_bindx(sk, addr, count, SCTP_BINDX_ADD_ADDR); if (-1 == error) tst_brkm(TBROK, tst_exit, "bindx (add): %s", strerror(errno)); return error; } static inline int test_listen(int sk, int backlog) { int error = listen(sk, backlog); if (-1 == error) tst_brkm(TBROK, tst_exit, "listen: %s", strerror(errno)); return error; } static inline int test_connect(int sk, struct sockaddr *addr, socklen_t addrlen) { int error = connect(sk, addr, addrlen); if (-1 == error) tst_brkm(TBROK, tst_exit, "connect: %s", strerror(errno)); return error; } static inline int test_connectx(int sk, struct sockaddr *addr, int count) { int error = sctp_connectx(sk, addr, count, NULL); if (-1 == error) tst_brkm(TBROK, tst_exit, "connectx: %s", strerror(errno)); return error; } static inline int test_accept(int sk, struct sockaddr *addr, socklen_t *addrlen) { int error = accept(sk, addr, addrlen); if (-1 == error) tst_brkm(TBROK, tst_exit, "accept: %s", strerror(errno)); return error; } static inline int test_send(int sk, const void *msg, size_t len, int flags) { int error = send(sk, msg, len, flags); if (len != error) tst_brkm(TBROK, tst_exit, "send: error:%d errno:%d", error, errno); return error; } static inline int test_sendto(int sk, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { int error = sendto(sk, msg, len, flags, to, tolen); if (len != error) tst_brkm(TBROK, tst_exit, "sendto: error:%d errno:%d", error, errno); return error; } static inline int test_sendmsg(int sk, const struct msghdr *msg, int flags, int msglen) { int error = sendmsg(sk, msg, flags); if (msglen != error) tst_brkm(TBROK, tst_exit, "sendmsg: error:%d errno:%d", error, errno); return error; } static inline int test_recv(int sk, void *buf, size_t len, int flags) { int error = recv(sk, buf, len, flags); if (-1 == error) tst_brkm(TBROK, tst_exit, "recv: %s", strerror(errno)); return error; } static inline int test_recvmsg(int sk, struct msghdr *msg, int flags) { int error = recvmsg(sk, msg, flags); if (-1 == error) tst_brkm(TBROK, tst_exit, "recvmsg: %s", strerror(errno)); return error; } static inline int test_shutdown(int sk, int how) { int error = shutdown(sk, how); if (-1 == error) tst_brkm(TBROK, tst_exit, "shutdown: %s", strerror(errno)); return error; } static inline int test_getsockopt(int sk, int optname, void *optval, socklen_t *optlen) { int error = getsockopt(sk, SOL_SCTP, optname, optval, optlen); if (error) tst_brkm(TBROK, tst_exit, "getsockopt(%d): %s", optname, strerror(errno)); return error; } static inline int test_setsockopt(int sk, int optname, const void *optval, socklen_t optlen) { int error = setsockopt(sk, SOL_SCTP, optname, optval, optlen); if (error) tst_brkm(TBROK, tst_exit, "setsockopt(%d): %s", optname, strerror(errno)); return error; } static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id) { int error = sctp_peeloff(sk, assoc_id); if (-1 == error) tst_brkm(TBROK, tst_exit, "sctp_peeloff: %s", strerror(errno)); return error; } 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, uint32_t context) { int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no, timetolive, context); if (len != error) tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d", error, errno); return error; } static inline int test_sctp_send(int s, const void *msg, size_t len, const struct sctp_sndrcvinfo *sinfo, int flags) { int error = sctp_send(s, msg, len, sinfo, flags); if (len != error) tst_brkm(TBROK, tst_exit, "sctp_send: error:%d errno:%d", error, errno); return error; } static inline int test_sctp_recvmsg(int sk, void *msg, size_t len, struct sockaddr *from, socklen_t *fromlen, struct sctp_sndrcvinfo *sinfo, int *msg_flags) { int error = sctp_recvmsg(sk, msg, len, from, fromlen, sinfo, msg_flags); if (-1 == error) tst_brkm(TBROK, tst_exit, "sctp_recvmsg: %s", strerror(errno)); return error; } static inline void *test_malloc(size_t size) { void *buf = malloc(size); if (NULL == buf) tst_brkm(TBROK, tst_exit, "malloc failed"); return buf; } void test_check_msg_notification(struct msghdr *, int, int, uint16_t, uint32_t); void test_check_buf_notification(void *, int, int, int, uint16_t, uint32_t); void test_check_msg_data(struct msghdr *, int, int, int, uint16_t, uint32_t); void test_check_buf_data(void *, int, int, struct sctp_sndrcvinfo *, int, int, uint16_t, uint32_t); void *test_build_msg(int); void test_enable_assoc_change(int); void test_print_message(int sk, struct msghdr *msg, size_t msg_len); int test_peer_addr(int sk, sctp_assoc_t asoc, sockaddr_storage_t *peers, int count); #endif /* __sctputil_h__ */ lksctp-tools-1.0.16+dfsg.orig/ChangeLog0000644000175000017500000013730412300634451017461 0ustar michaelmichaelVersion 1.0.16 of the Developers' Release of the SCTP Linux Kernel Implementation is available from http://www.kernel.org lksctp-1.0.16: Tue Feb 18 11:01 EDT 2014 T:APP Code cleanups T:APP Various sctp_status fixes T:TEST Avoid using file descriptor 0 to get ENOTSOCK T:TEST Various fixes T:LIB Fix build for prefixed architectures lksctp-1.0.15: Sun May 12 11:01 EDT 2013 T:BUILD Allow build with no AM_SILENT_RULES support T:APP Fix sctp_status T:APP Fix quoted command line arguments lksctp-1.0.14: Wed Apr 05 11:54 EDT 2013 T:BUILD Modernize and fix autotool's build system T:TEST Fix threading test T:TEST Zero out flags in sendrecvmsg test T:HDR Sync header with the kernel lksctp-1.0.13: Wed Jan 23 12:13 EDT 2013 T:BUILD Use silent rules T:BUILD Fix build warnings all over the place T:APP Fix memory leak in sctp_xconnect T:TEST Fix deprecated values in test cases lksctp-1.0.12: Tue Jan 08 10:45 EDT 2013 T:API Add needed definitions for DTLS/SCTP. T:API Fix data corruption in sctp_send T:API Implement private SCTP_GET_ASSOC_STATS option to fetch addition association data. T:TEST Add more options to conformace test tool. T:APP Add HEARTBEAT command to sctp_darn T:API Obsolete interefaces have been removed T:API Suport for SCTP_SACK_IMMEDIATELY options T:API Support for non-blocking sctp-connectx lksctp-2.6.28-1.0.11: Wed Oct 21 16:53:41 EDT 2009 T:BUILD fix parallel build warning T:BUILD fix make distcheck for lksctp-tools T:BUILD fix compiler warnings in the libraray, apps and tests T:API Update the sctp.h header to match the kernel. lksctp-2.6.28-1.0.10: Fri Mar 27 11:15:25 EDT 2009 T:TEST Split the kernel frame test framework from lksctp-tools. The framework is very sensitive to all kernel changes, not just ones related to SCTP. As such, it has been a gating fractor to the releases of the new tools. T:APP New tool sctp_status to be used with SCTP conformance tests. http://networktest.sourceforge.net/ T:APP Add -T option to sctp_test T:APP Fix the -e option to sctp_darn T:LIB Fix building of static libraries. T:LIB Fix compile warning in addrs.c T:APP Update the application useage of sctp_connectx T:TEST Update the sctp_connectx() functional tests. T:API Update to the sctp_connectx(). Now takes additional argument. T:API Let sctp_recvmsg() honor passed in MSG_ flags K: See kernel change log for details. We'll track only tools changes here from now on. lksctp-2.6.26-1.0.9: Sun Jul 13 14:51:29 PDT 2008 T:Patch Make frame tests work with 2.6.26 kernel. T:Patch Implement and export SCTP-AUTH API extensions based on sctpsocket-16 draft T:NA Process withsctp.in at build time K:Patch Add documentation for sctp sysctl variable K:NA Mark the tsn as received after all allocations finish K:NA Make sure N * sizeof(union sctp_addr) does not overflow. K:NA Correclty set changeover_active for SFR-CACC K:NA Correctly cleanup procfs entries upon failure. K:NA Fix ECN markings for IPv6 K:NA Flush the queue only once during fast retransmit. K:NA Start T3-RTX timer when fast retransmitting lowest TSN K:NA Correctly implement Fast Recovery cwnd manipulations. K:NA Move sctp_v4_dst_saddr out of loop K:NA retran_path update bug fix K:NA Fix NULL dereference of asoc. K:NA Fix use of uninitialized pointer K:NA Add address type check while process paramaters of ASCONF chunk K:NA Do not enable peer IPv6 address support on PF_INET socket K:NA Initialize partial_bytes_acked to 0, when all of the data is acked K:NA IPv4 vs IPv6 addresses mess in sctp_inet[6]addr_event. K:NA Fix compiler warning about const qualifiers K:NA Fix protocol violation when receiving an error lenght INIT-ACK K:NA Add check for hmac_algo parameter in sctp_verify_param() K:Patch New sctp mailing list K:NA Remove an unused parameter from sctp_cmd_hb_timer_update K:Patch "list_for_each()" -> "list_for_each_entry()" where appropriate. K:NA Correct /proc/net/assocs formatting error K:Patch Use snmp_mib_{init,free}(). K:Patch Remove useless assignment from __sctp_rcv_lookup_endpoint K:NA fix wrong debug counting of bind_bucket K:NA fix wrong debug counting of datamsg K:Patch Replace socket with sock for SCTP control socket. K:Patch Use inet_ctl_sock_create for control socket creation. K:Patch Remove sctp_add_cmd_sf wrapper bloat K:Patch Remove redundant wrapper functions. K:Patch Replace char msg[] with static const char[] K:NA Fix a race between module load and protosw access K:NA fix misannotated __sctp_rcv_asconf_lookup() K:NA Fix local_addr deletions during list traversals. K:Patch Bring MAX_BURST socket option into ietf API extension compliance K:NA Fix chunk parameter processing bug K:Patch Kill unused static inline sctp_sysctl_jiffies_ms K:Patch extend exported data in /proc/net/sctp/assoc K:Patch Use proc_create to setup de->proc_fops. K:Patch Update AUTH structures to match declarations in draft-16. K:NA Incorrect length was used in SCTP_*_AUTH_CHUNKS socket option K:Patch Clean up naming conventions of sctp protocol/address family registration K:NA Correctly set the length of sctp_assoc_change notification K:NA Pick up an orphaned sctp_sockets_allocated counter. K:Patch Convert sctp_dbg_objcnt to seq files. K:Patch Use snmp_fold_field instead of a homebrew analogue. K:NA Make sure the chunk is off the transmitted list prior to freeing. K:NA Fix kernel panic while received ASCONF chunk with bad serial number K:NA Set ports in every address returned by sctp_getladdrs() K:NA Correctly reap SSNs when processing FORWARD_TSN chunk K:NA Fix kernel panic while received AUTH chunk with BAD shared key identifier K:NA Fix kernel panic while received AUTH chunk while enabled auth K:Patch Kill silly inlines in ulpqueue.c K:NA Do not increase rwnd when reading partial notification. K:Patch Stop claiming that this is a "reference implementation" K:NA Fix miss of report unrecognized HMAC Algorithm parameter K:NA Correctly initialize error when parameter validation failed. K:Patch Follow Add-IP security consideratiosn wrt INIT/INIT-ACK K:Patch Implement ADD-IP special case processing for ABORT chunk K:Patch Change use_as_src into a full address state K:Patch Update ASCONF processing to conform to spec. K:Patch ADD-IP updates the states where ASCONFs can be sent K:Patch Update association lookup to look at ASCONF chunks as well K:Patch Add the handling of "Set Primary IP Address" parameter to INIT K:Patch Handle the wildcard ADD-IP Address parameter K:Patch Discard unauthenticated ASCONF and ASCONF ACK chunks K:Patch Use crc32c library for checksum calculations. K:Patch Use ipv4_is_ lksctp-2.6.24-1.0.8: Fri Feb 01 14:55:00 EST 2008 K:NA Add back the code that accounted for FORWARD_TSN parameter in INIT. K:NA Correctly handle AUTH parameters in unexpected INIT K:NA Fix the name of the authentication event. K:NA Spelling fixes K:NA Flush fragment queue when exiting partial delivery. K:NA Fix the bind_addr info during migration. K:NA Add bind hash locking to the migrate code K:NA Fix build issues with SCTP AUTH. K:NA Fix chunk acceptance when no authenticated chunks were listed. K:NA Fix the supported extensions paramter K:NA Fix SCTP-AUTH to correctly add HMACS paramter. K:NA Fix the number of HB transmissions. K:NA Add missing "space" K:NA Always flush the queue when uncorcking. K:NA Clean-up some defines for regressions tests. K:NA Fix PR-SCTP to deliver all the accumulated ordered chunks K:NA Make sctp_verify_param return multiple indications. K:NA Convert custom hash lists to use hlist. K:NA Use hashed lookup when looking for an association. K:NA Fix a potential race between timers and receive path. K:NA Allow ADD_IP to work with AUTH for backward compatibility. K:NA Correctly disable ADD-IP when AUTH is not supported. K:NA Update RCU handling during the ADD-IP case K:NA Fix difference cases of retransmit. K:NA Fix to process bundled ASCONF chunk correctly K:NA Fix bad formatted comment in outqueue.c Patch Use the {DEFINE|REF}_PROTO_INUSE infrastructure K:NA SCTP endianness annotations regression K:NA net/sctp/auth.c: make 3 functions static K:NA #if 0 sctp_update_copy_cksum() K:NA Consolidate sctp_ulpq_renege_xxx functions Patch port randomization Patch Tie ADD-IP and AUTH functionality as required by spec. Patch API updates to suport SCTP-AUTH extensions. Patch Implement the receive and verification of AUTH chunk Patch Enable the sending of the AUTH chunk. Patch Implement SCTP-AUTH parameter processing Patch Implement SCTP-AUTH initializations. Patch Implement SCTP-AUTH internals Patch protocol definitions for SCTP-AUTH implementation K:NA Move sysctl_sctp_[rw]mem definitions to protocol. Patch Implement the Supported Extensions Parameter K:NA net/sctp/socket.c: make 3 variables static K:NA Make sctp_addto_param() static. Patch Rewrite of sctp buffer management code K:NA Add paramters validity check for ASCONF chunk K:NA Discard OOTB packetes with bundled INIT early. K:NA Clean up OOTB handling and fix infinite loop processing K:NA Explicitely discard OOTB chunks K:NA Send ABORT chunk with correct tag in response to INIT ACK K:NA Validate buffer room when processing sequential chunks K:NA Convert bind_addr_list locking to RCU K:NA Add RCU synchronization around sctp_localaddr_list K:NA Fix to handle invalid parameter length correctly K:NA Abort on COOKIE-ECHO if backlog is exceeded. K:NA Correctly disable listening when backlog is 0. K:NA Do not retransmit chunks that are newer then rtt. K:NA Uncomfirmed transports can't become Inactive K:NA Pick the correct port when binding to 0. K:NA Use net_ratelimit to suppress error messages print too fast K:NA Fix to encode PROTOCOL VIOLATION error cause correctly K:NA Fix sctp_addto_chunk() to add pad with correct length K:NA Assign stream sequence numbers to the entire message K:NA properly clean up fragment and ordering queues during FWD-TSN. K:NA remove useless code in function sctp_init_cause K:NA drop SACK if ctsn is not less than the next tsn of assoc K:NA IPv4 mapped addr not returned in SCTPv6 accept() K:NA Fix whitespace errors. lksctp-2.6.22-1.0.7: Thu Jul 12 12:24:14 EDT 2007 K:NA Don't disable PMTU discovery when mtu is small K:NA Flag a pmtu change request K:NA Update pmtu handling to be similar to tcp K:NA Fix leak in sctp_getsockopt_local_addrs when copy_to_user fails K:NA Allow unspecified port in sctp_bindx() K:NA Correctly set daddr for IPv6 sockets during peeloff K:NA Do not include ABORT chunk header in the notification. K:NA Correctly copy addresses in sctp_copy_laddrs. K:NA Prevent OOPS if hmac modules didn't load K:NA Set assoc_id correctly during INIT collision. K:NA Re-order SCTP initializations to avoid race with sctp_rcv() K:NA Fix the SO_REUSEADDR handling to be similar to TCP. K:NA Verify all destination ports in sctp_connectx. K:NA Fix sctp_getsockopt_local_addrs_old() to use local storage. K:NA Implement SCTP_MAX_BURST socket option. K:NA Implement sac_info field in SCTP_ASSOC_CHANGE notification. K:NA Honor flags when setting peer address parameters K:NA Implement SCTP_ADDR_CONFIRMED state for ADDR_CHNAGE event. K:NA Implement SCTP_PARTIAL_DELIVERY_POINT option. K:NA Implement SCTP_FRAGMENT_INTERLEAVE socket option K:NA Do not interleave non-fragments when in partial delivery K:NA Unmap v4mapped addresses during SCTP_BINDX_REM_ADDR operation. K:NA Fix assertion (!atomic_read(&sk->sk_rmem_alloc)) failed message K:NA Correctly reset ssthresh when restarting association K:NA Reset some transport and association variables on restart K:NA Increment error counters on user requested HBs. K:NA Cleanup stale data during association restart K:NA Strike the transport before updating rto. K:NA Fix connection hang/slowdown with PR-SCTP. K:NA Force update of the rto when processing HB-ACK K:NA Fix SACK sequence during shutdown. K:NA Correctly handle unexpected INIT-ACK chunk. K:NA Verify some mandatory parameters. K:NA Set correct error cause value for missing parameters K:NA Fix err_hdr assignment in sctp_init_cause. T:NA Add support for sctp_getaddrlen() API. K,T:NA Fix typo adaption -> adaptation as per the latest API draft. K:NA Don't export include/linux/sctp.h to userspace. K,T:NA Add support for SCTP_CONTEXT socket option. K:NA Enable auto loading of SCTP when creating an ipv6 SCTP socket. K:NA Handle address add/delete events in a more efficient way. K:NA SCTP endianness annotations. K:NA Cleanup of the sctp state table code. K:NA Remove temporary associations from backlog and hash. K:NA Correctly set IP id for SCTP traffic. K:NA Always linearize packet on input. K:NA Fix the RX queue size shown in /proc/net/sctp/assocs output. K:NA Fix receive buffer accounting. K:NA Do not timestamp every SCTP packet. K:NA Use correct mask when disabling PMTUD. K:NA Include sk_buff overhead while updating the peer's receive window. K:NA Enable Nagle algorithm by default. K:NA Remove multiple levels of msecs to jiffies conversions. K:NA Use the flags value that is passed as an arg to sctp_accept. K:NA Fix IPv6 address flag setting when doing peel-off/accept. K:NA Cleanup nomem handling in the state functions. K:NA Extend /proc/net/sctp/snmp to provide more statistics. K:NA Convert SCTP to use the new HMAC template and hash interface. K:NA Fix sctp_primitive_ABORT() call in sctp_close(). K:NA Fix sctp_make_abort_user() to avoid use of buggy get_user_iov_size(). K:Bug 1502698 ADDIP: Don't use an address as source until it is ASCONF-ACKed. K:NA Set chunk->data_accepted only if we are going to accept it. K:NA Verify all the paths to a peer via heartbeat before using them. K:NA Unhash the endpoint in sctp_endpoint_free(). K:NA Check for NULL input to sctp_bucket_destroy(). K:NA Fix persistent slowdown in sctp when a gap ack consumes rx buffer. K:NA Send only 1 window update SACK per message. K:NA Don't do CRC32C checksum over loopback. K:NA Reset rtt_in_progress for the chunk when processing its sack. K:NA Reject sctp packets with broadcast addresses. K:NA Limit association max_retrans setting in ASSOCINFO setsockopt. T:NA updates to linux 2.6.17 K:NA Allow linger to abort 1-N style sockets. K:NA Validate the parameter length in HB-ACK chunk. K:NA A better solution to fix the race between sctp_peeloff() and sctp_rcv(). K:Bug 1439226 Set sk_err so that poll wakes up after a non-blocking connect failure. K:NA Fix state table entries for chunks received in CLOSED state. K:NA Fix panic's when receiving fragmented SCTP control chunks. K:NA Prevent possible infinite recursion with multiple bundled DATA. K:NA Allow spillover of receive buffer to avoid deadlock. T:NA Fix the type of 'len' argument in sctp_recvmsg() man page. lksctp-2.6.16-1.0.6: Fri Feb 3 10:54:20 PST 2006 K:NA Fix 'fast retransmit' to send a TSN only once. K:NA Heartbeats exceed maximum retransmission limit. K:NA Correct the number of INIT retransmissions. K:NA Fix sctp_rcv_ootb() to handle the last chunk of a packet correctly. K:NA Fix couple of races between sctp_peeloff() and sctp_rcv(). K:NA Fix machine check/connection hang on IA64. K:NA Fix bad sysctl formatting of SCTP timeout values on 64-bit m/cs. K:NA Fix sctp_assoc_seq_show() panics on big-endian systems. K:NA sctp doesn't show all associations/endpoints in /proc. K:NA Fix sctp_cookie alignment in the packet. K:NA Fix potential race condition between sctp_close() and sctp_rcv(). K,T:NA Add support for SCTP_DELAYED_ACK_TIME socket option. K,T:NA Update SCTP_PEER_ADDR_PARAMS socket option to the latest api. draft11. lksctp-2.6.15-1.0.5: Tue Jan 3 15:49:27 PST 2006 K:NA Fix SCTP to not return erroneous POLLOUT events. K:NA Fix getsockname for sctp when an ipv6 socket accepts a connection from an ipv4 socket. K:NA Return socket errors only if the receive queue is empty. K,T:NA Include ulpevents in socket receive buffer accounting. K:Bug 1350514 Fix ia64 NaT consumption fault with sctp_sideeffect commands. K:NA Remove timeouts[] array from sctp_endpoint. K:Bug 1350521 Fix potential NULL pointer dereference in sctp_v4_get_saddr. K:NA Do not allow unprivileged programs initiating new assocs on privileged ports. K:NA Allow SCTP_MAXSEG to revert to default frag point with a '0' value. K:NA Fix SCTP_SETADAPTION sockopt to use the correct structure. K,T:NA Rename SCTP specific control message flags to use SCTP_ prefix rather than MSG_ prefix. lksctp-2.6.14-1.0.4: Fri Oct 28 10:56:04 PDT 2005 T:NA Add sctp_send() API support, testcases and manpage. T:NA Add preprocessor constants for PR-SCTP, ADDIP & CANSET_PRIMARY K,T:NA Fix SCTP socket options to work with 32-bit apps on 64-bit kernels. K,T:NA Fix sctp_get{pl}addrs() API to work with 32-bit apps on 64-bit kernels. T:NA Ignore MSG_CMSG_COMPAT flag leaked to 32-bit userspace with 64-bit kernels <= 2.6.13. K,T:Bug 1122994Fix SCTP_SHUTDOWN notifications for 1-1 style sockets. lksctp-2.6.13-1.0.3: Thu Sep 1 10:54:22 PDT 2005 T:NA Update to 2.6.13 K:NA Fix potential NULL pointer dereference while handling an ICMP error. K:NA Make init & delayed sack timeouts configurable by user. K:NA Fix incorrect setting of sk_bound_dev_if when binding/sending to a ipv6 link local address. K:NA Support IP_FREEBIND socket option and ip_nonlocal_bind sysctl. K:NA Extend the info exported via /proc/net/sctp to support netstat for SCTP. K:NA Support SO_BINDTODEVICE option on incoming packets. K:Bug 120804 Fix bug in restart of peeled-off association. K,T:NA sctp_connectx() support. T:NA Increase sk_sndbuf to address send buffer accounting changes. T:NA Update SCTP internet drafts in doc directory T:NA Fix inconsistencies in license stmt in the library files. K:Bug 1155119 Add sctp send buffer accounting. K:NA Replace incorrect use of dev_alloc_skb with alloc_skb in sctp_packet_transmit(). K:NA Fix bug in sctp_init() error handling code. K:NA Use ipv6_addr_any() rather than ipv6_addr_type() in sctp_v6_is_any(). T:Bug 1150885 Fix subscript out of range bug in sctp_test.c K:Bug 1158878 Implement Sec 2.41 of SCTP Implementers guide. K:Bug 1121085 Fix SCTP_ASSOCINFO getsockopt for 1-1 style sockets. K:Bug 1155130 Add sctp receive buffer accounting. lksctp-2.6.10-1.0.2: Thu Dec 30 15:55:27 PST 2004 Bug 1074664 Fix sctp_getladdrs() to return valid local addresses on an endpoint that is bound to INADDR_ANY or inaddr6_any. NA Update to 2.6.10 Bug 1028605 Fix misc. issues in SCTP_PEER_ADDR_PARAMS set socket option. NA Fix bug in setting ephemeral port while adding a bind address. Bug 1090392 Clean up the T3_rtx timer when deleting a transport. Patch 1090027Implementation of SCTP IG Section 2.35 Bug 905731 Validate and respond to invalid chunk/parameter lengths. Bug 1085959 Treat ICMP protocol unreachable errors from non-SCTP capable hosts as ABORTs. NA Code cleanup: remove unused code and make needlessly global code static Bug 1058857 Fix potential null pointer dereference in sctp_err_lookup(). Bug 982971 Validate fromlen/msg_flags in sctp_recvmsg before dereferencing. Bug 860345 Fix invalid msg length to sctp_sendmsg in sctp_xconnect.c Bug 1008149 Fix HEARTBEAT_ACKs being sent to wrong dest. ip address in a multihoming scenario after failback. (Jorge) NA Update any transports that are caching a deleted address as a source address. NA Update cwnd/ssthresh as per the sctpimpguide modifications. NA Adaption layer indication support NA Change sctp_assoc_t to a sized type(s32) NA Update to 2.6.9 NA Update to 2.6.8-rc2 NA Mark chunks as ineligible for fast retransmit after handling retransmit. Bug 995918 Fix missing '+' in the computation of sack chunk size in sctp_sm_pull_sack(). NA Use idr_get_new_above() with a starting id of 1 to avoid returning an associd of 0. Bug 968562 Fix issues with handling stale cookie error over multihoming associations. Bug 991991 Fix data not being delivered in SHUTDOWN_SENT state. Bug 979178 Set/Get default SCTP_PEER_ADDR_PARAMS for endpoint when associd and peer address are 0. Bug 965359 Fix missing VTAG validation on certain incoming packets. Bug 965278 Fix to wakeup blocking connect() after max INIT retries failed. Bug 965276 Fix the use of cached non-zero vtag in a INIT that is resent after a stale cookie error. Bug 962587 Fix poll() on a 1-1 style socket so that it returns when the association is aborted by peer. Bug 962530 Add association states to netinet/sctp.h Bug 954271 Fix to not start a new association on a 1-many style sendmsg() with MSG_EOF/MSG_ABORT flag and no data. Bug 948012 Fix to not setup a new association if the endpoint is in SHUTDOWN_ACK_SENT state and recognizes that the peer has restarted. lksctp-2.6.6-1.0.1: Tue May 11 10:08:56 PDT 2004 Bug 949429 Fix multihomed connection failures on 64bit systems. (Vlad) Bug 932698 fix accessing gap ack blocks array with -ve index in sctp_outq_sack(). Bug 932692 memset parameter misordering. NA Fix the 3rd arg to sctp_recvmsg() to size_t instead of a ptr. NA Rename SCTP_ADDR_REACHBLE as SCTP_ADDR_AVAILABLE. NA Fix bugs in handling overlapping INIT and peer restart over a multi-homed association. NA SCTP crc table can be static const (Stephen Hemminger) NA Update sctp_test message sizes to match the new frag point of 1452 bytes for AF_INET sockets with 1500 mtu. NA Propagate error from sctp_proc_init. (Olaf Kirch) Patch 751951 Partial Reliability extension support. NA Cleanup sctp_packet and sctp_outq infrastructure. NA Avoid the use of constant SCTP_IP_OVERHEAD to determine the max data size in a SCTP packet. NA Add MSG_EOF to netinet/sctp.h NA Use id to ptr translation service to assign and validate assoc ids. NA Update sctp_ulpevent structure. NA Fix typo in entry name of remove_proc_entry() call. NA Enable association change and data io events in sctp_test. NA Add set_peer_primary interactive option to sctp_darn. NA Use AM_CFLAGS/AM_LDFLAGS in Makefile.am's. NA Avoid the use of hackish CONFIG_IPV6_SCTP__ option. NA Don't do any ppid byte-order conversions as it is opaque to SCTP. lksctp-2.6.3-1.0.0: Bug 905331 Fix incorrect sinit_max_init_timeo behavior. (samudrala) NA Force enable crypto options needed by SCTP (samudrala) NA Update to 2.6.3 (samudrala) NA Add support to get/set primary addr of an assoc to sctp_darn. NA Add __BEGIN_DECLS/__END_DECLS to sctp.h (Ian) NA Fix sctp_getladdrs()/sctp_getpaddrs() API so that the port value in the returned addresses is in network byte order. (samudrala) NA Fix SCTP_INITMSG set socket option so that a parameter with 0 value will not change its current value. (samudrala) NA Use __get_free_pages() to allocate ssnmap to avoid kmalloc's 128K limit. (samudrala) lksctp-2.6.2-0.9.0: NA Updated withsctp to capture and replace TCP_NODELAY setsockopt() (samudrala) Patch 890787 RPM packaging bugfixes. (FiX) NA Removed the deprecated ADLER32 checksum support. (samudrala) NA Update to 2.6.2 (samudrala) NA Added manpages for SCTP. (samudrala) Patch 887176 autoconf cleanup/ Initial RPM packaging (FiX) Patch 878417 Added new 1-1 style API testcases. (damien, samudrala) NA Add sysctl parameters to change socket receive/send buffer sizes and update the default receive buffer to 65535 bytes. NA provide valid tos and oif values for ip_route_output_key. NA Fix bugs in byte order conversion while processing certain address related socket options. (samudrala) Patch 869098 ADDIP: T4 RTO timer support. (kevin.gao) Patch 865250 withsctp: a tool to replace TCP with SCTP. (La Monte) NA Enable shared libraries in lksctp-tools. (FiX) Patch 843544 ADDIP: Process incoming ASCONF_ACK chunks. (kevin.gao) NA Add a testcase to verify that a SHUTDOWN_COMP notification is received on a SHUT_RW one-to-one style socket. (samudrala) NA Add peeloff test to src/apps. (samudrala) NA Fix overflow in the macros JIFFIES_TO_MSECS/MSECS_TO_JIFFIES when used with large values. (samudrala) NA Fix the duplicate increment of checksum error counter and counting bad packet errors as checksum errors. (samudrala) NA Fix to free assocs in the acceptq of a one-to-one style socket that is closed. (samudrala) NA ADDIP: Add sysctl parameter to enable/disable addip (samudrala) NA Fix extra semicolon bug in sctp_cacc_skip_3_1() (Ed Rupp) Patch 831522 ADDIP: Testcase for delete IP (kevin.gao) Patch 822546 ADDIP: Process ASCONF and respond with ASCONF_ACK (kevin.gao) lksctp-2.6.0-test7-0.7.4: NA Update SCTP tests so that they can be run under LTP (samudrala) NA Update to 2.6.0-test7 (samudrala) Patch 809137 ADDIP: Support to create ASCONF_ACK chunk. (kevin.gao) Patch 798988 ADDIP: ASCONF chunk send support. (kevin.gao) NA lksctp-tools tree re-organization (samudrala) NA Fix malloc calls in kernel tests with no error checks. (samudrala) NA Fix bugs in conversions between msecs and jiffies. (samudrala) NA Update to 2.6.0-test6 (samudrala) PARISC64 Convert tv_add() from a static inline to macro to fix an obscure assembler issue with parisc64 (samudrala) NA Update to 2.6.0-test5 (samudrala) PPC64 port Use correct types for args passed to sctp_recvmsg() calls. PPC64 port Change the last arg of sctp_opt_info() to match the last arg of getsockopt(). (samudrala) PPC64 port Don't overload the optval of ADDRS_NUM socket options with different types for input and output. (samudrala) lksctp-2_6_0-test4-0_7_3: NA draft 07 API: (samudrala) - listen() with 0 backlog disables listening. - By default all notifications are turned off even with one-to-many(UDP) style sockets. Bug 799468 Fixes for a couple of issues with ssnmap allocation. (samudrala) NA Convert sctp_param2sockaddr() and sockaddr2sctp_addr to address family specific routines. (samudrala) NA draft 07 API: sctp_bindx() update. (samudrala) Patch 791660 ADDIP: SCTP_SET_PEER_PRIMARY socket option support. (kevin.gao) NA Update to 2.6.0-test4 (samudrala) NA draft 07 API: getp/laddrs, freep/laddrs changes (samudrala) NA draft 07 API: sctp_recvmsg() arg type change. (samudrala) NA draft 07 API: sctp_peeloff() takes associd, not a ptr (samudrala) Patch 784504 ADDIP: Testcase to verify basic ADDIP functionality. (kevin.gao) Bug 787008 Bugs in sysctl set/get of sctp rto parameters. (samudrala) NA Update to 2.6.0-test3 (samudrala) Bug 783176 Fix to avoid large kmalloc failures on 64bit platforms (samudrala) Patch 776732 ADDIP basic infrastructure support. (ardelle.fan) Patch 775227 sctp_recvmsg() API support. (rlayer) lksctp-2_6_0-test1-0_7_2: NA Set output interface for link-local v6 addresses (jgrimm) Patch 769844 Add V6 and freebsd support to sctp_test (rlayer) Patch 772062 Support IPV6_V6ONLY socket option. (ardelle.fan) Patch 757888 Support v4-mapped-v6 addresses (ardelle.fan) NA Update API names to be compatible with draft07 (samudrala) NA Update to 2.6.0-test1 (samudrala) Patch 767208 Shutdown transport selection fix. (rlayer) Patch 769792 Fix for panic on recvmsg() with MSG_PEEK & misc stuff (samudrala) Patch 765676 Fix nasty race on skb destructor with AF_PACKET sockets (jgrimm) lksctp-2_5_72-0_7_1: Patch 759352 Perf: Don't search for gap ack blocks past highest TSN (jgrimm) Patch 758202 Perf: Remove update_pending() from SACK path (jgrimm) NA Update to 2.5.72 NA Fix hlist bug introduced by mainline kernel (jgrimm) NA sctp_xconnect test tool (rlayer) Patch 729089 ASSOCINFO/RTOINFO sockopts (pems & rlayer) NA Update to 2.5.71 (jgrimm) Bug 754129 Incorrect VTAG in stale cookie error chunk (samudrala) Patch 749587 Change rto sysctl vars to milliseconds (rmlayer) Patch 752321 Add kamikaze test. (ardelle.fan) Bug 752808 Bug fix for input loop exiting too early on TCP-style (jgrimm) lksctp-2_5_70-0_7_0: NA Fix hostname parameter handling, should ABORT (jgrimm) NA Fix ft_frame_unkparam testcase (rlayer) Bug 751458 Fixes from InterOp (jgrimm, samudrala) Bug 746295 Fix div by 0 in sctp_jitter (jgrimm) NA Make T5 timer cleanup SHUTDOWN-PENDING state. (jgrimm) Patch 744633 /proc interface to display associations/endpoints (samudrala) NA Update to 2.5.70 kernel. (samudrala) NA sctp_getladdrs(), sctp_getpaddrs() bug fixes. (samudrala) Patch 738592 sctp_sendmsg() api support. (ardelle.fan) Patch 738550 SCTP_SHUTDOWN_EVENT notification support. (samudrala) NA Rename struct sctp_protocol as sctp_globals (samudrala) Patch 737395 SCTP_GET_PEER_ADDR_INFO socket option. (samudrala) Bug 695324 Report error cause in CANT_STR_ASSOC (ardelle.fan) Bug 695322 Stale cookie might not be first err cause (ardelle.fan) Patch 735933 Support for socket options that take addr & associd (samudrala) Patch 718726 Add CACC frametest (ardelle.fan) NA slab cache for chunks & bind_bucket (jgrimm) NA Update to 2.5.69 kernel. (samudrala) Patch 733320 SCTP ECN & IPv6 (jgrimm) NA Bug in get_peer_addr_params. (jgrimm, report by yfj@stanford.edu) Patch 730924 Add sinfo_timetolive support. (jgrimm) Patch 730461 SO_LINGER support for TCP-style sockets. (samudrala) Bug 729234 Initialize missing v4 fields of a v6 accept socket (samudrala) Bug 729652 Free chunk(s) when primitive_SEND fails (jgrimm) Patch 704841 SEND_FAILed for fragmented messages (jgrimm, ardelle.fan) Patch 727821 sendmsg() updates for TCP-style sockets. (samudrala) Patch 727454 Add control chunk bundling (jgrimm) Patch 718726 Add SFR-CACC support. (ardelle.fan) Patch 726343 Add SCTP_MAXSEG support. (jgrimm) NA Add some macros to help cleanup code. (jgrimm) Patch 725367 Fix for poll() on a TCP-style listening socket. (samudrala) Patch 725219 Add per message fragment tracking (jgrimm) NA Update to 2.5.68 kernel. (samudrala) lksctp-2_5_67-0_6_9: Patch 723414 Handle accept() of a CLOSED association. (samudrala) Patch 722206 shutdown() support for TCP-style sockets. (samudrala) Bug 722169 Fix can't send to routed ipv6 address bug (jgrimm) NA Fix GFP_KERNEL allocation while spinlock. (jgrimm) Patch 721330 Allow v4 private to v4 global association. (jgrimm) Patch 720930 getsockname/getpeername support for TCP-style sockets (samudrala) Patch 719232 optimization: csum_update_copy && ulpq short-circuit (jgrimm) NA Update to 2.5.67 kernel. (samudrala) Patch 717587 Use kernel crypto api (jgrimm) Patch 714270 listen backlog support for TCP-style sockets. (samudrala) Patch 712929 Fix SACK bundling bug & a few minor fixes (jgrimm) Patch 711590 Add V6_LINKLOCAL & sin6_scope_id support. (jgrimm) Patch 711584 Add '--interface' option to sctp_darn tool. (jgrimm) Patch 704841 Add SEND_FAILED support (ardelle.fan) NA Update to 2.5.66 kernel (jgrimm) Patch 709527 Add icmpv6 handler and PKT_TOOBIG support. (jgrimm) lksctp-2_5_65-0_6_8: Patch 706470 Bundle SACK with outgoing DATA (jgrimm) NA Add --echo option to sctp_darn (jgrimm) NA Update to 2.5.65 kernel and config changes. (jgrimm) Patch 702439 New kernel test to verify TCP-style socket interfaces. (samudrala) Bug 701294 Invalid associd passed to getsockopt() in sctp_darn. (samudrala) lksctp-2_5_64-0_6_7: NA Update to 2.5.64 kernel. (samudrala) Bug 699299 Panic in close(). (jgrimm) Patch 698437 frametest for TCP-style sockets. (samudrala) Patch 698877 Receiver SWS prevention. (jgrimm) Patch 689872 Nagle-like support for SCTP. (ardelle.fan) Patch 694884 accept() support for TCP-style sockets. (samudrala) NA Bug fix from mailing list (Norbert Kiesel) Patch 689872 SCTP_NODELAY testcases (ardelle.fan) lksctp-2_5_63-0_6_6: NA Update to 2.5.63 kernel. (samudrala) Patch 692590 Add set/getsockopt SET_PEER_PRIMARY_ADDR (jgrimm) Bug 601470 Fix PF_INET sockets advertise v6 support bug (jgrimm) NA Fix testframe for non-SMP build (jgrimm) Bug 688408 Fix testcases for v4 only configurations (jgrimm) Patch 677351 Add getsockopt for DEFAULT_SEND_PARAM (ardelle.fan) Patch 689446 Renege for "fills gap" case. (jgrimm) Bug 611888 Round-robin retransmit path updates. (samudrala) NA Update to 2.5.61 kernel. (samudrala) NA Update to 2.5.60 kernel. (samudrala) Bug 649355 v6 source address selection support. (samudrala) Patch 680361 Add testcase for partial data delivery. (jgrimm) Patch 677351 SET_DEFAULT_SEND_PARAM setsockopt. (ardelle.fan) Patch 681914 Skinny up ulpevent and support sinfo_cumtsn (jgrimm) Patch 685246 Partial Data Delivery. (jgrimm). Patch 683736 Override primary destination with MSG_ADDR_OVER (ardelle.fan) Patch 630124 SCTP snmp mib statistics update/display support. (samudrala) Patch 686131 Move duplicate TSN tracking to tsnmap & cleanup (jgrimm) NA C99 struct initializer cleanup. (Art Haas) lksctp-2_5_59-0_6_5: Patch 674359 Handling for Invalid Stream in INIT & missing cookie. (jgrimm) Patch 676473 Add v6 scoping testcases. (jgrimm) Bug 677107 af->dst_saddr doesn't fill in the port (samudrala) Patch 676468 Cleanup of assoc bind addr list initialization (samudrala) Patch 678481 Large Message Fragmentation support (jgrimm) Bug 679839 Kconfig can emit bad config of ipv6=m, sctp=y (jgrimm) lksctp-2_5_59-0_6_4: Patch 673715 Fix to update rwnd on partial reads. (samudrala) Patch 673678 Minor fixes to overlapping init. (jgrimm) Patch 673309 Minor fixes to icmp error handler. (samudrala) Bug 672878 Free chunks in rtx & control queues on teardown.(samudrala) Patch 672759 Advisory marker as 'unsafe' for unload. (jgrimm) Patch 671916 Heartbeat timer during shutdown fixes (jgrimm) Patch 670970 Path mtu support for v4 addresses. (samudrala) NA Update to 2.5.59 kernel. (samudrala) Patch 667038 Add heartbeat jitter (ardelle.fan) Patch 670020 Remove hardcoded stream limits (jgrimm) NA Update to 2.5.56 kernel. (samudrala) Patch 662296 Handle ip re-assembled non-linear skb's (samudrala) Patch 663633 get/free paddrs and laddrs support (ardelle.fan) Bug 664112 Retransmitting already gap-acked TSNs (jgrimm) NA Update to 2.5.53 kernel. (samudrala) Bug 667037 ft_frame_rwnd_receiver fail with v4 only (ardelle.fan) lksctp-2_5_52-0_6_3: NA Update to 2.5.52 kernel. (samudrala) Patch 652802 Window update SACK support. (samudrala) Patch 651063 Fixes for compiler issues with gcc 3.2 (samudrala) Patch 649819 Notifier registration for v6 addr events. (samudrala) Patch 638235 Stale cookie support. (ardelle.fan) Patch 648103 v6 source address selection support. (samudrala) Bug 645067 memcpy in sctp_sendmsg() may copy too much. (samudrala) NA Update to 2.5.50 kernel. (samudrala) Patch 644936 SCTP_INITMSG socket option. (samudrala) NA Update to 2.5.49 kernel. (samudrala) Bug 641066 Bad dereference in sctp_cmd_assoc_failed. (samudrala) Patch 639177 MSG_PEEK support for recvmsg(). (samudrala) lksctp-2_5_47-0_6_2: Patch 637943 MSG_EOR support for recvmsg(). (samudrala) NA Update to 2.5.47 kernel. (samudrala) Patch 636734 v6 autobind (jgrimm) Patch 635797 Blocking connect() support. (samudrala) Patch 634730 udp-style connect(non-blocking) support. (samudrala) NA Update to 2.5.46 kernel. (samudrala) Patch 555335 Peer address parameters socket option (ardelle) NA Update to 2.5.45 kernel. (samudrala) Patch 631750 sctpParam_t cleanup (jgrimm) Bug 587078 sctp_process_init() can fail (jgrimm) Patch 633338 Handle HOST_NAME_ADDR parm and misc. (jgrimm) Patch 625413 sockaddr_storage_t cleanup (jgrimm) Patch 635246 short circuit "no route" case (jgrimm) Bug 581734 PF_INET6 listen can't receiving v4 addresses (jgrimm) lksctp-2_5_44-0_6_1: Patch 628901 Initial Source address selection support. (samudrala) Bug 611930 Lost CWR scenario fix (jgrimm) NA 2.5.44 (jgrimm) Patch 628333 SNMP MIB infrastructure for SCTP. (nivedita) Patch 628318 Checks for tcp-style sockets. (nivedita) Bug 547270 Retain the order of retransmission. (daisyc) Patch 622919 Handle User initiated ABORT. (ardelle.fan) Bug 611927 Bug in the calculation of highest new tsn in sack. (samudrala) Bug 611916 Data can end up getting sent ahead of pend. rtx data (jgrimm) NA Update to 2.5.43 kernel. (samudrala) Bug 623286 SHUTDOWN_COMPLETE has 0 vtag on lost SDC + restart. (samudrala) Patch 601756 VTAG checks for ABORT and SHUTDOWN_COMPLETE chunks. (ardelle.fan) Patch 619993 Fixes a couple of sctp_peeloff() issues. (samudrala) Bug 611919 Fast retranmist should ignore cwnd limit. (daisyc) Bug 611840 Restart address needs to check INIT and happen earlier (jgrimm) lksctp-2_5_41-0_6_0: NA Update to 2.5.41 kernel (samudrala) Bug 621054 v6 kernel tests pass without IPv6 configured. (daisyc) NA Update to 2.5.40 kernel (jgrimm) NA Split into user/kernel repositories (inaky, daisyc) Bug 611928 Alloc GFP_KERNEL with locks held (jgrimm) Bug 602650 Dropping packets > frag_point (jgrimm, samudrala) Patch 601367 Handle Unrecognized Parms (daisyc) Patch 609744 Add abort and shutdown to sctp_darn (ardelle.fan) Bug 604251 Association freed twice (jgrimm) Bug 611835 Fix Restart address check (jgrimm) lksctp-2_5_29-0_5_0: Patch 588249 misc. user header file fixes (jgrimm) lksctp-2_5_29-0_4_99: Patch 582166 sctp_peeloff() support. (samudrala) Bug 583874 sendmsg/init with bad buf. has leak (jgrimm) Patch 581963 Handle select/poll syscalls (daisyc) Bug 583798 Need GFP_ATOMIC when BH disabled (samudrala) Bug 585351 MSG_UNORDERED not set on fragmented chunks (samudrala) Patch 585474 Remove old DEFAULT_STREAM sock opt (jgrimm) Bug 585653 Fix V6INADDR_ANY to choose a saddr (jgrimm) Bug 585929 more leaks in sendmsg() on error cases. (samudrala) Patch 574420 overlapping init/restart (dajiang, jgrimm) Bug 581992 zero probe shouldn't error association (samudrala) Patch 587986 move to Linux 2.5.29 (samudrala) lksctp-2_5_24-0_4_12: Patch 569943 graceful shutdown of an individual association. (samudrala) Patch 572054 move to linux kernel 2.5.24. (samudrala) Bug 574069 bugs in fragmentation & reassembly. (samudrala) Patch 579301 check for No User Data error and testcase (jgrimm) Bug 574071 less strict rwnd check at rcvr (samudrala) Patch 579525 SCTP_AUTOCLOSE socket option. (samudrala) Patch 575712 modify sctp_darn tool to use select (daisyc) NA misc.: cleanup jiffies decl., update docs. (jgrimm) Patch 581745 getsockname needs sk->sport (jgrimm) Patch 582273 handle DATA while in SHUTDOWN-SENT (jgrimm) Bug 581997 sctp_wait_for_sndbuf fault (jgrimm) Patch 573958 Overlapping Init testcases (dajiang) Patch 582905 misc: remove md5 files. update cause code values (jgrimm) lksctp-2_5_15-0_4_11: Patch 560341 assoc_hash and more locking (jgrimm) Bug 541062 local_addr_list not not writer safe (jgrimm) Patch 564637 new ep_hash and locking down address list read/writes (jgrimm) Patch 565087 protect against timer overfiring (jgrimm) Patch 565935 Collapse ep/asoc hash links into common substructure (jgrimm) Bug 565868 Ctl-sock (OOTB) traps sending to ipv6 dest. (jgrimm) Bug 565878 Xmit to wrong peer when no asoc. (jgrimm) Patch 565686 Update RTO upon Heartbeat ACK. (samudrala) Patch 567028 Cleanup unneeded atomic_t fields (jgrimm) Patch 567061 Some sctp-socket-04.txt updates (jgrimm) Patch 567646 Combine sctp_func_t/sctp_af_specific_t (jgrimm) Patch 568562 Sysctl support for RFC 2960 variables (jgrimm) Patch 567514 SCTP_SET_EVENTS sock options (samudrala) Patch 567492 block/non-block send and SNDBUF/RCVBUF (daisyc) lksctp-2_5_15-0_4_10: Patch 561757 congestion control, handle SACKs indicating renege (samudrala) Patch 561632 v4 scoping rules (daisyc) lksctp-2_5_15-0_4_9: Patch 554705 Locking phase 1 (off the BH, use socklock and backlog) (jgrimm) Bug 550363 Shutdown handling of CTSN incorrect (jgrimm) Patch 558565 testframe ipv4 only, doesn't compile (samudrala) Patch 556572 Fix INADDR_ANY and some IPv4 scoping (daisyc) Patch 559801 Cleanup old locking stuff and various naming/style (jgrimm) lksctp-2_5_15-0_4_8: Patch 557034 Port to 2.5.15 (samudrala) Patch 550903 sys_bindx removal (inaky, samudrala) lksctp-2_4_18-0_4_8: Patch 546328 sctp_transport cleanup (jgrimm) Bug 545852 sk->err cleanup (samudrala) Bug 547147 association leaks the inqueue->in_progress chunk (jgrimm) Bug 541065 fix port_rover race conditition in bind path (jgrimm) Patch 544577 heartbeat ack and failover (dajiang) NA Make lksctp a module (inaky) NA bindx over sockopt (inaky) Patch 547885 Split out v6 code and cleanup module patch (jgrimm) Patch 544583 ft_frame_hbACK updates (dajiang, huang) Patch 547340 fix testframe for "run once" (samudrala) Patch 548772 sctp_lock primitives (jgrimm) Patch 547319 naming cleanup in statefuns (daisyc) Patch 549266 sctp_lock unittests (jgrimm) Patch 548815 Disable fragments option and more tests. (samudrala) Patch 550400 Add OOTB testcase (daisyc) Patch 550520 transport & association error thresholds (samudrala) NA fix ft_frame_init_timer to not conflict with OOTB (jgrimm) Patch 549356 Small fixes and cleanup of bindx code (inaky) Patch 549360 bindx through sockopt (inaky) Patch 551716 Start using sctp_opts field instead of endpoint (jgrimm) Patch 551657 RTT Measurements and RTO updates (samudrala) Patch 552084 sctp_endpoint_common (jgrimm) Patch 553100 Testcase for RTT Measurements (samudrala) Bug 553329 Sendmsg + INIT CMSG has path which can corrupt assoc (jgrimm) Patch 553394 Move sctp_association to use endpoint_common (jgrimm) Patch 553528 rtx and heartbeat failures cleanup (samudrala) Patch 553844 OOTB packet processing (daisyc) lksctp-2_4_18-0_4_7: Bug 541198 Old-style retval->state races with CMD (jgrimm) Patch 541820 listen auto-bind support (samudrala) Patch 543421 Complete removal of retval structs/processing (jgrimm) Patch 544908 Object Count Debugging facilities (jgrimm) Patch 544806 Fix inqueue leak of chunks (daisyc) Patch 544460 Fragmentation/Reassembly support (samudrala) lksctp-2_4_18-0_4_6: Patch 529522 Primary Addr from saddr (jgrimm, daisyc, hui_huang) Patch 529530 Use skb_copy_datagram_iovec (samudrala) Patch 529961 sctphdr, PARAM constants in net order (jgrimm) Patch 529707 Changes to sctp_make_data* interfaces (samudrala) Patch 531206 Massive linux/sctp.h changes (jgrimm) Patch NA Eliminate sctp_io.h (jgrimm) Patch 532575 sctp_opt as a per socket structure (jgrimm) Patch 532245 Patch to eliminate tcp_func dependency (samudrala) Patch 533351 Update headers to Socket Extensions 03 draft (jgrimm) Patch 531647 Initialize MTU from routing information (samudrala) Patch NA Update csum I-D. (jgrimm) Patch 529783 Send heartbeats (dajiang, hui_huang) Bug 529726 SACK response sent to incorrect dest (jgrimm) Patch NA More cleanup, mostly naming, dead field removal. (jgrimm) Bug 539452 sk->err should have errno as positive value (jgrimm). lksctp-2_4_18-0_4_5: Bug 513536 association lookup can fail (jgrimm) NA Unused file/header cleanup (jgrimm) NA Move sctp_socket() to testframe (jgrimm) Patch 524687 Stop byteswapping the rcv skb part 1 (daisyc) Patch 525009 Stop byteswapping the rcv skb part 2 (daisyc) NA Change CRC32C per Connectathon (jgrimm) Patch 526505 Change crc code to skip checksum field (jgrimm) Patch 526177 Incorrect use of skb->end (samudrala) Patch 526740 Missing bindx support (samudrala) NA A few sctp_darn fixes (jgrimm) NA updatelinux_sctp.sh to handle links (loretos) Patch 513912 Invalid stream verification (daisyc) Patch 528541 ABORT handling during initiation phase (jgrimm) Patch 528679 Misc. Cleanup. (jgrimm) Patch 528611 Fix testframe skb for fraglist support (samudrala) Patch 526156 SCTP_STATUS sockopt (samudrala) lksctp-2_4_17_0-4_4: Patch 515054 INIT retransmission (jgrimm) Patch 511394 Invalid StreamId tests (daisyc) README suggestions (baqaqi) Bug 519410 test_kernel spinlock initialization (sridhar) Patch 520992 Enable COOKIE-ECHO bundling (jgrimm) Patch 520627 Fix autobind twice bug (daisyc) Patch 520755 A couple bugs from Debug Memory Allocations (sridhar) Patch 521216 Fix bind_addrs_to_raw calling kmalloc(GFP_KERNL) on int. (jgrimm) lksctp-2_4_17-0_4_3: New Update to 2.4.17 (sridhar) Patch 512680 Frame test bindx for IPv6 (hui) Patch 510317 Failing testcase for source addr bug (daisyc) lksctp-2_4_1-0_4_3: Patch 511028 New CRC32C (dinakarjb) Patch 510797 Sendmsg w/associd (jgrimm) Patch 499262 Testcase for stream negotiation (daisyc) Bug 473322 Sendmsg insists on msg_name (jgrimm) If you would like to follow the day-to-day development of the SCTP kernel, refer to: http://lists.sourceforge.net/lists/listinfo/lksctp-developers Post messages for the developers (including bug reports) to lksctp-developers@lists.sourceforge.net If you wish to participate in development, please subscribe to the developers' list, drop a note to lksctp-developers. lksctp-tools-1.0.16+dfsg.orig/README0000644000175000017500000001546112300634451016566 0ustar michaelmichael(C) Copyright 2007 Hewlett-Packard Development Company, L.P. (C) Copyright IBM Corp. 2001, 2003 Copyright 2001 Motorola, Cisco, Intel, Nokia, La Monte Yarroll. Copyright 2002 Nokia, La Monte Yarroll, Intel. This is the lksctp-tools package for Linux Kernel SCTP Reference Implementation. This package is intended to supplement the Linux Kernel SCTP Reference Implementation now available in the Linux kernel source tree in versions 2.5.36 and following. For more information on LKSCTP see the below section titled "LKSCTP - Linux Kernel SCTP." lksctp-tools ____________ The lksctp-tools package is intended for two audiences. 1) SCTP application developers 2) LKSCTP project developers For SCTP application developers, this package provides the user-level C language header files and a library for accessing SCTP specific application programming interfaces not provided by the standard sockets. For LKSCTP project developers, this package provides the API regression and functional tests. Developers should also check lksctp_tests package that provides low level kernel tests. These are available from git.kernel.org. For either role, this project provides sample code, utilities, and tests that one may find useful. LKSCTP - Linux Kernel SCTP __________________________ The Linux Kernel SCTP Reference 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. For more information on licensing terms, please see the file COPYING in this directory. SCTP (Stream Control Transmission Protocol) is a message oriented, reliable transport protocol, with congestion control, support for transparent multi-homing, and multiple ordered streams of messages. RFC2960 defines the core protocol. The IETF SIGTRAN Working Group developed SCTP. The primary architects are Randy Stewart and Qiaobing Xie. The Kernel Reference is first and foremost an exposition of RFC2960 and related documents. You will find that the comments and variable names tie closely back to the RFC and Internet Drafts. This work was started by a small team of developers at Motorola. Throughout this document, "we" refers to that team. We intend for the meaning of "we" to expand to include the whole development community, all 27 million programmers on the planet. The Kernel Reference has loose origins in the SCTP User Space Reference by Randy Stewart and Qiaobing Xie. MANIFEST -------- . |-- bin |-- doc |-- man |-- src |-- apps |-- func_tests |-- include | `-- netinet |-- lib |-- testlib `-- withsctp You may want to check the following files: COPYING.lib Licensing terms of libsctp COPYING Licensing terms of other pieces of the package ROADMAP A tour around the files in the distribution of SCTP-tools. INSTALL How to install and run this beast. ChangeLog What has changed since the last release? DESIGN GOALS ------------ - A primary design goal is to reflect RFC 2960 as closely as practical. We have changed many names from the user space reference to follow the draft as closely as possible. We have also included extensive quotes from the draft adjacent to the code which implements them. - The other primary design goal is to integrate Linux kernel data structures and idioms as much as possible. The test framework (in directory test/) provides many of the functions which would otherwise come from the kernel. The test frame does use libc features, but the state machine code should be libc-free. - A lesser design goal is to completely describe the actions for each state transition in an sctp_command_t (see sctp_command.h). This means that the state functions (sctp_state_fn_t in sctp_sm.h) are NOT allowed to modify their endpoint, association, or chunk arguments. This is enforced by const modifiers--please respect the compiler warnings. All actions must be described in the last argument to the state function. - A byte order convention for dealing with the SCTP chunk headers: all SCTP chunks, regardless if the chunk is to be sent outbound to the network or was received inbound from the network, the header portion of the chunk is ALWAYS created and retained in the NETWORK BYTE ORDER. - An error code handling convention is to return negative values internally. The sk->err field holds a positive valued errno values, so will need our internal values negated. - We are moving toward an XP development model. So far we have adopted pair-programming, coding-to-test (functional and unit), design through refactoring, and story-based planning. In order to make XP work, it is very important that we have a complete set of tests for the code. We can not safely refactor major parts of the code without a way to find the things we break. If you decide to extend the SCTP Kernel Implementation we ask that you do the following: 1) Pick an XP story. Tell lksctp-developers@lists.sourceforge.net 2) Write a functional test for that XP story. The functional test defines "DONE" for the story. 3) Submit the functional test as a patch on SourceForge. 4) Write unit tests for any new "objects" you define. 5) Implement your feature. 6) Submit the feature and the unit tests as a separate SourceForge patch. Look in src/func_tests and in lksctp-tests package for examples of of tests. Please do not submit code that fails its own tests or any of the unit tests. If it fails a functional test, please document that with the submission. Another XP requirement is to code only what is you need to make the current test work. Where this means omitting required features, we have put in prominent BUG comments describing the omitted functionality. FEATURES -------- This implementation uses a fairly compact cookie which is isolated in its own substructure of SCTP_association. We have been moving toward aggregating data elements which need to travel together to minimize copying of individual elements in favour of more efficient structure copies. You will find what we believe to be the smallest possible Internet simulator in the middle of the function test_kernel.c:simulate_internet(). The simulator makes a few simplifying assumptions... MAILING LISTS and WEB SITES --------------------------- http://www.sourceforge.net/projects/lksctp This is the lksctp project webpage. lksctp-developers@lists.sourceforge.net This is the discussion list for developers. Join this list if you are interested in following the day-to-day activities of the SCTP Kernel Reference Implementation development community. See subscription directions at: http://lists.sourceforge.net/lists/listinfo/lksctp-developers http://www.sctp.org This is Randy Stewart's SCTP web site. http://sctp.de This is Michael Tuexen's SCTP web site. Michael has collected dozens of documents related to SCTP. lksctp-tools-1.0.16+dfsg.orig/AUTHORS0000644000175000017500000000214612300634451016752 0ustar michaelmichaelThe initial developer and founder of the project: ------------------------------------------------- La Monte H.P. Yarroll Current Maintainer: ------------------- Vlad Yasevich Daniel Borkmann Previous Maintainers: -------------------- Sridhar Samudrala Jon Grimm Contributors: ------------- Karl Knutson Xingang Guo Daisy Chang Inaky Perez-Gonzalez Hui Huang Dajiang Zhang Ryan Layer Francois-Xavier Kowalski Frank Filz Ivan Skytte Jorgensen Neil Horman Michael Biebl Wei Yongjun Sam Miller Andrei Pelinescu-Onciul Michele Baldessari Michael Tuexen Fan Du Are you missing? drop us a line! lksctp-tools-1.0.16+dfsg.orig/bootstrap0000755000175000017500000000040312300634451017637 0ustar michaelmichael#!/usr/bin/env bash # -*- sh -*- set -ex # exit on error libtoolize --force --copy aclocal autoheader automake --foreign --add-missing --copy autoconf if [ "$1" = "-a" ]; then ./configure --prefix=/usr --enable-shared --enable-static make make dist fi lksctp-tools-1.0.16+dfsg.orig/stamp-h.in0000644000175000017500000000001212300634451017571 0ustar michaelmichaeltimestamp lksctp-tools-1.0.16+dfsg.orig/Makefile.rules0000644000175000017500000000046512300634451020475 0ustar michaelmichael# -*-makefile-*- # # Generate pre-parsed C code. %.i: %.c $(COMPILE) -E -c $^ -o $@ .PRECIOUS: %.i %.ci: %.i -grep -v -e "^#" -e "^ *$$" $^ | indent > $@ mv -f $@ $^ ## FIXME: Your stuff here edit = @sed \ -e "s|\@bindir\@|$(bindir)|" \ -e "s|\@libdir\@|$(libdir)|" \ -e "s|\@PACKAGE\@|$(PACKAGE)|" lksctp-tools-1.0.16+dfsg.orig/Makefile.vars0000644000175000017500000000050312300634451020307 0ustar michaelmichael# -*-makefile-*- # # type: deep, strictness: gnu MAINTAINERCLEANFILES = Makefile.in DISTCLEANFILES = \\\#*\\\# Makefile CLEANFILES = MOSTLYCLEANFILES = *~ *.[aios] *.bak *.ci *.io EXTRA_DIST = LATEX = @LATEX@ DVIPS = @DVIPS@ DVIPDFM = @DVIPDFM@ ENSCRIPTBIN = @ENSCRIPTBIN@ PS2PDF = @PS2PDF@ ## FIXME: Your stuff here lksctp-tools-1.0.16+dfsg.orig/ROADMAP0000644000175000017500000000227012300634451016706 0ustar michaelmichaelTOUR ---- COPYING.lib Licensing terms of libsctp COPYING Licensing terms of other pieces of the package README Read this before developing. ChangeLog What has changed since the last release? AUTHORS Developers name list. INSTALL How to build and install this package. doc/ All the relevant Internet Drafts and RFC's. doc/states.txt This is a detailed state table for SCTP. It makes a pretty good index for RFC2960 too... man/ SCTP man pages src/ Implementation of the user space library, include files - this should go, some day, into glibc - as well as a set of SCTP test tools and test programs. src/apps SCTP test applications. src/func_tests SCTP functional tests. src/lib Sources for SCTP library libsctp.a. src/testlib Sources for SCTP test library libsctputil.a. src/include/netinet Header files needed for user space development. bin/ Scripts for lksctp build, installation and execution. test/ Testframe functional and unit tests. These tests use a framework which enables running lksctp code in userspace. test/linux/include This include heirarchy includes special versions of kernel include files needed by the user-space test frame. lksctp-tools-1.0.16+dfsg.orig/COPYING.lib0000644000175000017500000005755412300634451017517 0ustar michaelmichael GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. lksctp-tools-1.0.16+dfsg.orig/NEWS0000644000175000017500000000044212300634451016376 0ustar michaelmichael The Linux Kernel SCTP Reference Implementation release 0.5.0 is included in Linux 2.5 Kernel release 2.5.34 and up. From release 0.6.0 and on, we will adopt the new build and installation process for lksctp users and developers. Please check the INSTALL and ROADMAP for more details. lksctp-tools-1.0.16+dfsg.orig/Makefile.am0000644000175000017500000000111512300634451017731 0ustar michaelmichaelinclude $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules DISTCLEANFILES += config.h stamp-h libtool MAINTAINERCLEANFILES += aclocal.m4 config.h.in configure stamp-h.in \ config.h stamp-h EXTRA_DIST += ChangeLog AUTHORS COPYING COPYING.lib INSTALL \ README ROADMAP NEWS \ Makefile.vars Makefile.rules Makefile.dirs # bin or src products may be required to generate stuff in test/ SUBDIRS = man bin src doc ACLOCAL_AMFLAGS=-I m4 # Libtool support LIBTOOL_DEPS = @LIBTOOL_DEPS@ libtool: $(LIBTOOL_DEPS) $(SHELL) ./config.status --recheck ## FIXME: Your stuff here lksctp-tools-1.0.16+dfsg.orig/doc/0000755000175000017500000000000012304140712016440 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/doc/ols.sty0000644000175000017500000000420212300634451020000 0ustar michaelmichael % TEMPLATE for Usenix papers, specifically to meet requirements of % TCL97 committee. % originally a template for producing IEEE-format articles using LaTeX. % written by Matthew Ward, CS Department, Worcester Polytechnic Institute. % adapted by David Beazley for his excellent SWIG paper in Proceedings, % Tcl 96 % turned into a smartass generic template by De Clarke, with thanks to % both the above pioneers % use at your own risk. Complaints to /dev/null. % make it two column with no page numbering, default is 10 point % adapted for Ottawa Linux Symposium % include following in document. %\documentclass[twocolumn]{article} %\usepackage{usits,epsfig} \pagestyle{empty} %set dimensions of columns, gap between columns, and space between paragraphs %\setlength{\textheight}{8.75in} \setlength{\textheight}{9.0in} \setlength{\columnsep}{0.25in} \setlength{\textwidth}{6.45in} \setlength{\footskip}{0.0in} \setlength{\topmargin}{0.0in} \setlength{\headheight}{0.0in} \setlength{\headsep}{0.0in} \setlength{\oddsidemargin}{0in} %\setlength{\oddsidemargin}{-.065in} %\setlength{\oddsidemargin}{-.17in} \setlength{\parindent}{0pc} \setlength{\parskip}{\baselineskip} % started out with art10.sty and modified params to conform to IEEE format % further mods to conform to Usenix standard \makeatletter %as Latex considers descenders in its calculation of interline spacing, %to get 12 point spacing for normalsize text, must set it to 10 points \def\@normalsize{\@setsize\normalsize{12pt}\xpt\@xpt \abovedisplayskip 10pt plus2pt minus5pt\belowdisplayskip \abovedisplayskip \abovedisplayshortskip \z@ plus3pt\belowdisplayshortskip 6pt plus3pt minus3pt\let\@listi\@listI} %need a 12 pt font size for subsection and abstract headings \def\subsize{\@setsize\subsize{12pt}\xipt\@xipt} %make section titles bold and 12 point, 2 blank lines before, 1 after \def\section{\@startsection {section}{1}{\z@}{24pt plus 2pt minus 2pt} {12pt plus 2pt minus 2pt}{\large\bf}} %make subsection titles bold and 11 point, 1 blank line before, 1 after \def\subsection{\@startsection {subsection}{2}{\z@}{12pt plus 2pt minus 2pt} {12pt plus 2pt minus 2pt}{\subsize\bf}} \makeatother lksctp-tools-1.0.16+dfsg.orig/doc/random_notes.txt0000644000175000017500000006240712300634451021706 0ustar michaelmichaelThese are more random design notes I need to keep track of. Perhaps counterWork() should be replaced with direct counter manipulation. This violates the functional style of the state functions, but only a little bit... IRRELEVANT: The vtag return value should be subsumed into repl. IRRELEVANT: sctp_make_chunk() should NOT be called directly from these IRRELEVANT: functions. I am very unhappy with retval->link. That means a LOT of copying. DONE: Basic principle for host or network byte order: DONE: Network byte order should be as close to the network as DONE: possible. DONE: This means that the first routine to manipulate a particular header DONE: should convert from network byte order to host byte order as DONE: soon as it removes it gets it from the next lowest layer. DONE: Outbound, the last routine to touch a header before passing it DONE: to the next lower layer should convert it to network order. For DONE: queues, the routine at the top (closer to user space) does the DONE: conversion--inbound queues are converted to host order by the DONE: reader, outbound queues are converted to network order by the DONE: writer. DONE: DONE: Forget that smoke. The problem is that this entails reparsing the DONE: header when it comes time to pass it to the lower layer (e.g. you need DONE: to check the SCTP header for optional fields). The code which fills DONE: in a field should put it in network order. DONE: DONE: POSSIBLY on inbound, the code which parses the header should convert DONE: it to host order... But on outbound, packets should ALWAYS be in DONE: network byte order! OK, we need to add some stream handling. This means that we are updating sctp_create_asoc() among many other functions. I think we want some functions for dereferencing streams... DONE: NOTES FOR TSNMap DONE: DONE: Variables: DONE: uint8_t *TSNMap Array counting #chunks with each TSN DONE: uint8_t *TSNMapEnd TSNMap+TSN_MAP_SIZE DONE: uint8_t *TSNMapOverflow counters for TSNMapBase+TSN_MAP_SIZE; DONE: uint8_t *TSNMapCumulativePtr Cell for highest CumulativeTSNAck DONE: uint32_t TSNMapCumulative Actual TSN for *TSNMapCumulativePtr DONE: uint32_t TSNMapBase Actual TSN for *TSNMap DONE: long TSNMapGap chunk.TSN - TSNMapBase DONE: DONE: Constants: DONE: TSN_MAP_SIZE DONE: DONE: TSNMap and TSNMapOverflow point at two fixed buffers each of length DONE: TSN_MAP_SIZE. When TSNMapCumulativePtr passes TSNMapEnd (i.e. we send DONE: the SACK including that value), we swap TSNMap and TSNMapOverflow, DONE: clearing TSNMap. DONE: DONE: This work should be done OUTSIDE the state functions, as it requires DONE: modifying the map. It is sufficient for the state function to return DONE: TSNMapGap. Take care that TSNMapGap is never 0--we reserve this value DONE: to mean "no TSNMapGap". DONE: FIGURE THIS OUT--which structures represent PEER TSN's and which DONE: structures represent OUR TSN's. DONE: DONE: Rename the elements to peerTSN* and myTSN*. ERROR IN Section 6.1: Note: The data sender SHOULD NOT use a TSN that is more than 2**31 - 1 above the beginning TSN of the current send window. SHOULD be 2**16-1 because of the GAP ACKs. ERROR IN 12.2 Parameters necessary per association (i.e. the TCB): Ack State : This flag indicates if the next received packet : is to be responded to with a SACK. This is initialized : to 0. When a packet is received it is incremented. : If this value reaches 2 or more, a SACK is sent and the : value is reset to 0. Note: This is used only when no DATA : chunks are received out of order. When DATA chunks are : out of order, SACK's are not delayed (see Section 6). NOWHERE in Section 6 is this mentioned. We only generate immediate SACKs for DUPLICATED DATA chunks. Is this an omission in Section 6 or a left-over note in section 12.2? Section 6.1: Before an endpoint transmits a DATA chunk, if any received DATA chunks have not been acknowledged (e.g., due to delayed ack), the sender should create a SACK and bundle it with the outbound DATA chunk, as long as the size of the final SCTP packet does not exceed the current MTU. See Section 6.2. I definately won't do this. What AWFUL layering! We have this REALLY WIERD bugoid. We SACK the first data chunk of the second packet containing data chunks. A careful reading of the spec suggests that this is legal. It kinda works, but we end up with more SACK timeouts than we might otherwise have... The fix is to split off the SACK generation code from the TSN-handling code and run it when we get either a NEW packet, or an empty input queue. OK: Section 6.2 does not explicitly discuss stopping T3-rtx. The worked OK: example suggests that T3-rtx should be canceled when the SACK is OK: lined up with the data chunk... Ah! Section 6.3... We really ought to do a sctp_create_* and sctp_free_* for all of the major objects including SCTP_transport. {DONE: Copy af_inet.c and hack it to support SCTP. If we were going to do SCTP as a kernel module, we'd do this: We can then socket.c:sock_unregister() the whole INET address family and then sock_register() our hacked af_inet... } SCTP_ULP_* is really two groups of things--request types and response types... DONE: We want to know whether the arguments to bind in sock.h:struct proto DONE: are user space addresses or kernel space addresses. To do that we DONE: want to find the tcp bind call. To do THAT we are looking for the DONE: place that struct proto *prot gets filled in for a TCP struct sock. API issue--how do you set options per association? Normal setsockopt will operate on an endpoint. This is mostly an issue for the UDP-style api. The current solution (v02) is that all associations on a single socket should all have the same options. I still don't like this. Write a free_endpoint(). Remember to free debug_name if allocated... DONE: Make sure that the API specifies a way for sendto() to use some kind DONE: of opaque identifier for the remote endpoint of an association. As DONE: observed before, it is a bad thing to use an IP address/port pair as DONE: the identifier for the remote endpoint... General BUG--sctp_bind() needs to check to see if somebody else is already using this transport address (unless REUSE_ADDR is set...)... sctp_do_sm() is responsible for actually discarding packets. We need a sctp_discard_packet_from_inqueue(). Be sure to schedule the top half handling in sctp_input.c:sctp_v4_rcv(). Keycode 64 is Meta_L, should be Backspace (or whatever that really is)... DONE: Should sctp_transmit_packet() clone the skb? [Yes. In fact we DONE: need a deep copy because of a bug in loopback. This problem DONE: sort of goes away with the creation of SCTP_packet.] - memcpy_toiovec() is for copying from a blob to an iovec... - after(), before(), and between() are for comparing 32bit wrapable numbers... Where do theobromides live? Are they fat soluable? printf "D %x\nC %x\nI %x\nP %x\nT %x\n", retval->skb->data, retval->chunk_hdr, retval->subh.init_hdr, retval->param_hdr, retval->skb->tail set $chunk = retval->repl->chunk_hdr set $init = (struct sctpInitiation *)(sizeof(struct sctpChunkDesc) + (uint8_t *)$chunk) set $param1 = (struct sctpParamDesc *)(sizeof(struct sctpInitiation) + (uint8_t *)$init) set $param2 = (struct sctpParamDesc *)(ntohs($param1->paramLength) + (uint8_t *)$param1) set $sc = (struct sctpStateCookie *)$param2 DONE: run_queue sctp_tq_sideffects needs while wrapper. OK: Important structures: OK: protocol.c: struct inet_protocol tcp_protocol (IP inbound linkage) OK: tcp_ipv4.c: struct proto tcp_prot (exceptions to inet_stream_ops) OK: af_inet.c: struct proto_ops inet_stream_ops (sockets interface) Another unimplemented feature: sctp_sendmsg() should select an ephemeral port if a port is not already set... Path MTU stuff: Send shutdown with rewound CumuTSNack. Is this a protocol violation? NO: Use larger TSN increment than 1? Allows subsequencing [This is NO: patently illegal. The correct solution involves MTU calculations...] Lowest of 3 largest MTU's for fragmentation? Probably. Allows 2 RWINs worth of backup? Immediate heartbeat on secondary when primary fails? (Use fastest response on heartbeat to select new primary, keeping MTU in mind) This is probably illegal. v13 added stricter rules about generating heartbeats. [p- use 3 largest RWINs to select...] [jm- pick top 3 thruputs (RWIN/Latency), pick lowest MTU for the new primary address ] Here is what we did to set up the repository: $ cd /usr/src/linux_notes $ bzcat ~/linux-2.4.0-test11.tar.bz2 | tar xfp - $ CVSROOT=:pserver:knutson@postmort.em.cig.mot.com:/opt/cvs $ export CVSROOT $ cd linux $ cvs import -m "plain old 2.4.0 test11" linux knutson start [Note that this EXCLUDES net/core.] $ cd .. $ mv linux linux-2.4.0-test11 $ cvs co linux $ cd linux-2.4.0-test11/net $ tar cfv - core | (cd ../../linux/net;tar xfp -) $ cd ../../linux $ cvs add net/core $ cvs add net/core/*.c $ cvs add net/core/Makefile $ cd net $ cvs commit -m "add core" $ cd .. [Now we create the branch.] $ cvs tag -b uml [Move to that branch.] $ cvs update -r uml $ touch foo $ bzcat ~/patch-2.4.0-test11.bz2 | patch -p1 $ for a in $(find . -newer foo | grep -v CVS); do echo $a; cvs add $a; done 2>&1 | tee ../snart $ cvs commit -m "UML patch for 2.4.0-test11" $ cvs tag latest_uml 2001 Jan 11 When we close the socket, it shouldn't de-bind the endpoint. Any new socket attempting to bind that endpoint should get an error until that endpoint finally dies (from all of its associations dying). This issue comes up with the question of what should happen when we close the socket and attempt to immediately open a new socket and bind the same endpoint. Currently, we could bind the same endpoint in SCTP terms which would be a new endpoint in data structure terms and buy ourselves some confusion. DONE: Tue Jan 16 23:08:51 CST 2001 DONE: DONE: We find that when we closed the socket (and nulled the ep->sk DONE: reference to it), we caused problems later on with chunks created for DONE: transmit. When we looked at TCP, we found that closing a TCP socket DONE: does not destroy it immediately--TCP also has post-close transactions. DONE: DONE: Solution: We use the ep->moribund flag to indicate when the socket is DONE: closed and do not immediately null the reference in ep. Wed Jan 17 01:21:40 CST 2001 What happens when loop1 == loop2 in funtest1b (i.e., when the source & destination endpoints are identical)? We found out. You get a *real* simultaneous init and a burning desire to designate two loop addresses so you don't inadvertently put yourself in the same situation again. We will investigate more later, as this situation promises to test a potential weak point in the protocol (cf. siminit above). Tue Jan 30 14:50:39 CST 2001 vendor: Linus release tag: linux-2_4_1 DONE: We really ought to have a small utility functions file for test stuff DONE: (both live kernel and test frame). Here are all the timers: T1-init (per association) T1-cookie (per association) T3-rtx (per destination) heartbeat timer (per association) T2-shutdown (per association) ?Per Destination Timer? (presumed to be T3-rtx) Mark each chunk with the transport it was transmitted on. When we transmit a chunk, we turn on the rtx timer for the destination if not on already. The chunk is then copied to q->transmitted. When we receive a sack, we turn off each timer corresponding to a TSN ACK'd by the SACK CTSN. This is because either everything got through, or the chunk outbound longest for a given destination got through. We then start the timers for destinations which still have chunks on q->transmitted, after moving the appropriate chunks to q->sacked. When a rtx timer expires for a destination, all the chunks on q->transmitted for that destination get moved to q->retransmit, which then get transmitted (a: at that time, b: when any chunks are transmitted, retransmissions go first, c: other). WHEN PUSHING A CHUNK FOR TRANMISSION WHEN TRANSMITTING A CHUNK Assign a TSN (if it doesn't already have one). Select a transport. If the T3-rtx for the transport is not running, start it. Make a copy to send. Move the original to q->transmitted. WHEN PROCESSING A SACK Walk q->transmitted, moving things to q->sacked if they were sacked. Walk chunk through q->sacked. if chunk->TSN <= CTSN { stop chunk->transport->T3RTX free the chunk } WHEN RTX TIMEOUT HAPPENS Walk chunk through q->transmitted if chunk->transport is the one that timed out, move chunk to q->retransmit. Trigger transmission. DONE: Cases for transport selection: DONE: 1) LUser is idiot savant, picks path DONE: 2) Transmit on primary path DONE: 3) Retransmit on secondary path sctp_add_transport() does not check to see if the transport we are adding already exists. This COULD lead to having to fail the same transport address twice (or more...). A valid INIT packet will not list the same address twice (in which case the OTHER guy is screwing himself) and we haven't implemented add_ip. THE PLAN (for adding lost packet handling): DONE: Initialize the timer for each transport when the transport is created. Generate timer control events according to 6.3.2. Write the state function for 6.3.3. Write the timer side-effects function. Here are random things we would put in an SCTP_packet: SCTP header contents: sh->source = htons(ep->port); sh->destination = htons(asoc->c.peerInfo.port); sh->verificationTag = htonl(asoc->c.peerInfo.init.initiateTag); A list of of chunks The total size of the chunks (incl padding) Here are random things we would do to an SCTP_packet: sctp_chunk_fits_in_packet(packet, chunk, transport) sctp_append_chunk(packet, chunk) sctp_transmit_packet(packet, transport) INIT_PACKET(asoc, &packet) /* Try to send a chunk down to the network. */ int sctp_commit_chunk_to_network(struct SCTP_packet *payload, struct SCTP_chunk *chunk, struct SCTP_transport *transport) { int transmitted; transmitted = sctp_append_chunk(payload, chunk, transport)) { switch(transmitted) { case SCTP_XMIT_PACKET_FULL: case SCTP_XMIT_RWND_FULL: sctp_transmit_packet(...); INIT_PACKET(payload); transmitted = sctp_append_chunk(payload, chunk, transport); break; default: break; /* Default is to do nothing. */ } return(transmitted); } sctp_append_chunk can fail with either SCTP_XMIT_RWND_FULL, SCTP_XMIT_MUST_FRAG (PMTU_FULL), or SCTP_XMIT_PACKET_FULL. /* This is how we handle the rtx_timeout single-packet-transmit. */ if (pushdown_chunk(payload, chunk, transport) && rtx_timeout) { return(error); } Thu Apr 5 16:04:09 CDT 2001 Our objective here is to replace the switch in inet_create() with a table with register/unregister methods. #define PROTOSW_PREV #define PROTOSW_NEXT struct inet_protosw inetsw[] = { {list: {next: PROTOSW_NEXT, prev: PROTOSW_PREV, }, type: SOCK_STREAM, protocol: IPPROTO_TCP, prot4: &tcp_prot, prot6: &tcpv6_prot, ops4: &inet_stream_ops, ops6: &inet6_stream_ops, no_check: 0, reuse: 0, capability: -1, }, #if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE) {type: SOCK_SEQPACKET, protocol: IPPROTO_SCTP, prot4: &sctp_prot, prot6: &sctpv6_prot, ops4: &inet_seqpacket_ops, ops6: &inet6_seqpacket_ops, no_check: 0, reuse: 0, capability: -1, }, {type: SOCK_STREAM, protocol: IPPROTO_SCTP, prot4: &sctp_conn_prot, prot6: &sctpv6_conn_prot, ops4: &inet_stream_ops, ops6: &inet6_stream_ops, no_check: 0, reuse: 0, capability: -1, }, #endif /* CONFIG_IP_SCTP || CONFIG_IP_SCTP_MODULE */ {type: SOCK_DGRAM, protocol: IPPROTO_UDP, prot4: &udp_prot, prot6: &udpv6_prot, ops4: &inet_dgram_ops, ops6: &inet6_dgram_ops, no_check: UDP_CSUM_DEFAULT, reuse: 0, capability: -1, }, {type: SOCK_RAW, protocol: IPPROTO_WILD, /* wildcard */ prot4: &raw_prot, prot6: &rawv6_prot, ops4: &inet_dgram_ops, ops6: &inet6_dgram_ops, no_check: UDP_CSUM_DEFAULT, reuse: 1, capability: CAP_NET_RAW, }, }; /* struct inet_protosw inetsw */ Here are things that need to go in that table: The first two fields are the keys for the table. struct inet_protosw { struct list_head list; unsigned short type; int protocol; /* This is the L4 protocol number. */ struct proto *prot; struct proto_ops *ops; char no_check; unsigned char reuse; int capability; }; Set type to SOCK_WILD to represent a wildcard. Set protocol to IPPROTO_WILD to represent a wildcard. Set no_check to 0 if we want all checksums. Set reuse to 0 if we do not want to set sk->reuse. Set 'capability' to -1 if no special capability is needed. * protocol = IPPROTO_TCP; /* Layer 4 proto number */ * prot = &tcp_prot; /* Switch table for this proto */ * sock->ops = &inet_stream_ops; /* Switch tbl for this type */ sk->num = protocol; - sk->no_check = UDP_CSUM_DEFAULT; - sk->reuse = 1; if (type == SOCK_RAW && protocol == IPPROTO_RAW) sk->protinfo.af_inet.hdrincl = 1; if (SOCK_RAW == sock->type) { if (!capable(CAP_NET_RAW)) goto free_and_badperm; if (!protocol) goto free_and_noproto; prot = &raw_prot; sk->reuse = 1; sk->num = protocol; sock->ops = &inet_dgram_ops; if (protocol == IPPROTO_RAW) sk->protinfo.af_inet.hdrincl = 1; } else { lookup(); } Supporting routines: int inet_protosw_register(struct inet_protosw *p); int inet_protosw_unregister(struct inet_protosw *p); Tue Apr 10 12:57:45 CDT 2001 Question: Should SCTP_packet be a dependent subclass of SCTP_outqueue, or should SCTP_outqueue and SCTP_packet be independent smart pipes which we can glue together? Answer: We feel that the independent smart pipes make independent testing easier. Sat Apr 21 18:17:06 CDT 2001 OK, here's what's going on. An INIT and an INIT ACK contain almost exactly the same parameters, except that an INIT ACK must contain a cookie (the one that the initiator needs to echo). In OUR implementation, we put the INIT packet in the cookie, so we really do most of the processing on the INIT when we get the COOKIE ECHO. Dilemma: When do we convert the INIT to host byte forder? We want to use the same code for all three cases: INIT, INIT ACK, COOKIE ECHO. But if we convert for INIT, then the INIT packet in the cookie (which is processed with the COOKIE ECHO) will be in host byte order. Options: 1. Leave the INIT in network byte order. All access must convert to host byte order as needed. Blech. This violates our existing conventions. Hmm. As long as we don't walk the parameters again, we might be OK... 2. Add an argument to sctp_process_param() telling whether or not to convert the parameter. We chose option 1. We REALLY should unify sctp_make_init() and sctp_make_init_ack(). The only difference is the cookie in the INIT ACK. We might one day need a version of sctp_addto_chunk() called sctp_addto_param() which does NOT add extra padding. How can we get the initial TSN in sctp_unpack_cookie without first having processed the INIT packet buried in the cookie? Sat Apr 28 15:03:48 CDT 2001 This MIGHT be a bug--look for places we use sizeof(struct iphdr)-- possibly we might need to grub around in the sk_buff structure to find the TRUE length of the iphdr (including options). One of the places is where we initialize a struct SCTP_packet--we really need to know how big the ip header options are. I've walked all the way through to the point where we pass INIT_ACK down to IP--it looks OK. We DO parse the parameters correctly... Two bugs--bind loop1a not loop1 in the second bind, and sctp_bind_endpoint() should not let you bind the same address twice. There should be an approriate errno in the bind man page. EINVAL. Tue May 15 15:35:28 CDT 2001 compaq3_paddedinitackOK.tcp We ignore ABORT. datakinectics_2 We will send extra data before we get a COOKIE ACK... We really lucked out and this implementation ran fine... sun (lost trace) We have an INIT that causes an oops. telesoft2_lostsendings.tcp telesoft3_spicyinitack.tcp This INIT ACK causes an oops. datakinectics_3 ulticom_3 They transmitted GAP reports and we retransmitted a TSN which had been gap ack'd. adax2_goodsend.tcp We produce MANY SACK's in a row after delaying way too long. The retransmissions did not get bundled. Mon May 21 17:06:56 CDT 2001 sctp_make_abort() needs to build an SCTP packet, not just a chunk... How do we handle cause codes? I don't know, but here's some random lines pruned from sctp_init_packet... packet->source_port = asoc->ep->port; packet->destination_port = asoc->peer.port; packet->verificationTag = asoc->peer.i.initiateTag; CHANGES NEEDED IN THE LINUX KERNEL to support SCTP: * - sockreg - both saddr and daddr need to be explicit arguments to the function which takes packets for transmission--move these OUT of the socket... Decouple d_addr from struct sock - bindx() - glue (elt in sk->tp_pinfo, etc...) We THINK we have the following items: - Per packet frag control (v6) - Unified PMTU discovery - iov-like sk_buff (to minimize copies) Fri Aug 17 10:58:35 CDT 2001 Current thinking: INADDR_ANY semantics for TCP imply an abstraction of the IP interfaces--use any that exist, TCP could care less. This means if you add or delete interfaces at a lower level, this doesn't require more configuration for TCP. What this means for SCTP is that INADDR_ANY should also abstract the IP interfaces, so that when an association is initiated, we use all available IP interfaces, even if some have been added or deleted since boot. At bind, we grub for all interfaces and add them to the endpoint. After bind, if an interface is added...we know about it because a) a connection came in on it and we're bound to INADDR_ANY--we add the new transport to the list and use that for the association. b) we initiate and...regrub for all existing interfaces? c) hooks may exist to inform us when new IP interfaces rise phoenix-like from the void (not pointer). Fri Aug 17 18:24:01 CDT 2001 We need to look in ip6_input.c for IPPROTO_TCP and IPPROTO_UDP. This probably needs to use the registration table to do some comparisons... There are several functions in tcp_ipv6.c that we want for sctp. They are currently static; we want them to be exported. Tue Aug 21 13:09:09 CDT 2001 This is a revised list of changes we need in the 2.4.x kernels to support SCTP. These are based in part on Bidulock's code: MUST HAVE: + inet_listen() hook for transport layer + Make tests for SOCK_STREAM more specific (add IPPROTO_TCP checks) ? Look for references to IPPROTO_TCP and IPPROTO_UDP to see if they are sufficiently uniform. REALLY OUGHT TO HAVE: - bindx() (Daisy) - sockreg (done, need to use) - netfilter Interface + inet_getname() hook for transport layer? - small & simple hooks here. + The ability to append things to proc files (/proc/sys/net specifically...) TCP-one-true-transport cruft - ip_setsockopt() hook (See SOCK_STREAM below.) - unified PMTU discovery (allegedly done, need to use) (See tcp_sync_mss) SOLUTIONS: - We could move the extension headers and PMTU stuff out to the socket. - We could intercept this socket call in sctp_setsockopt, and do the relevant fix up there. (LY characterizes as "flippin' disgusting") - We could use dst->pmtu (after all, TCP does...sort of...) Performance - decouple d_addr from struct sock (Andi Kleen) - zero-copy (done, need to use) - per packet IPv6 fragmentation control (allegedly done, need to use) - Why did LY ask for this--he doesn't recall... --------------------------------------------------------------------------- Tue Feb 10 11:26:26 PST 2004 La Monte One significant policy change which 1.0.0 should include is a bias toward performance issues. One principle I want to make sure survives performance improvements is readability. In particular, I still would like to put together a site hyperlinking LKSCTP with RFC2960 and supporting docs. It should be possible to ask "What code implements THIS section?" and "What mandated THIS piece of code?" Consequently, a performance enhancement should either improve readability or define a separate clearly marked fast-path. In particular, that class of speedups which collapses multiple decisions from different sections of the RFCs should probably use separate fast-path code. Separate fast-path code creates a maintenance problem, so fast-path code REALLY needs comments which point explicitly to the slow path. The slow- path code should where possible point to the corresponding fast path. It then becomes easier to check whether fixes for one path are relevant for the other as well. lksctp-tools-1.0.16+dfsg.orig/doc/style_guide.txt0000644000175000017500000001373412300634451021532 0ustar michaelmichaelThis is the style guide for the LKSCTP Project. 1.0 Introduction Use the Linux kernel coding style as the base, linux/Documentation/CodingStyle. This is intended as the IETF kernel reference code for RFC2960 and the SCTP API. As such, readability is paramount. We attempt to follow the names from RFC2960 as closely as practical given the constrains of C and the Linux kernel naming conventions. Here are the approximate naming rules we use. Those marked [obsolescent] will go away once we purge the last vestiges of them. 1) [obsolescent] If a name appears in RFC 2960 or the API draft we try to use it as closely as permitted by C syntax without ADDING "_". This usually means names of the form "xyzAbc". E.g. "Duplicate TSN" from RFC2960 became "DuplicateTSN", but "a_rwnd" is unaltered. New names should use this revised rule 1: If a name appears in RFC 2960 or the API draft we try to use it as closely as permitted by C syntax without using upper case letters. This usually means names of the form "xyz_abc". E.g. "Duplicate TSN" from RFC2960 became "duplicate_tsn", but "a_rwnd" is unaltered. Remember the acronyms still need to be upper case in comments. 2) [obsolescent] If a name refers to a struct which appears on the wire we use the form "struct xyzAbc". This is historically because we inherited most of these from the user space implementation. E.g. "struct sctpHeader". 3) There is no rule 3. 4) All functions start with "sctp_". Uh, yeah, well, uh... 5) Constants have the form "XYZ_ABC" per K&R. 6) [obsolecent] If "XYZ" is an acronym it SHOULD be capitalized as in "XYZ_abc" or "XYZabc" unless overridden by rule 2 or rule 4. E.g. "struct SCTP_association". New names should use this revised rule 6: Names with anronyms SHOULD map them to lower case, E.g. "struct sctp_association". 7) All remaining names SHOULD use the form "xyz_abc". E.g. "int too_big". 8) Deviations from these rules are bugs and need to be fixed. 2.0 Architectural and Procedural Standards The core metaphors are the state machine (sctp_do_sm(), related functions) and the smart pipe (inqueue, outqueue, ULPqueue, packet). The state machine breaks down into a pure functional core, sctp_sm_statefuns.c, with no side effects, and an explicit set of side effects, sctp_sm_sideeffects.c. Every function, typedef, enum, and struct needs a descriptive comment. 3.0 /* Comments */ Except as noted below, make all comments full sentences. Proper behaviour is to spell-cheque your comments. Those colourful American spellings will not be rejected. Start all sentences with a capital letter. Do not begin sentences with symbols which must be all lower case. Sentences end with a period, question mark, or exclamation point. Punctuation at the end of a sentence has two trailing spaces or a trailing newline. Comments should confine themselves to expressing the INTENT of the code. If comments do not agree with the code, then we have a BUG. Passive voice should be avoided. Every function, typedef, enum, and struct needs a descriptive comment. /* All comments are C comments, */ // not C++ comments. /* Multiline comments should * look like this. */ Every #endif should include a comment describing the matching #if. E.g. #if 0 #endif /* 0 */ A struct sk_buff_head needs a comment describing the REAL type of its elements. To disable a section of code use #if 0 #endif /* 0 */ rather than /* */. The if/endif pair safely interoperates with existing comments. 4.0 Appearance & Pretty printing Put a space after every keyword. Here is an example function: retval_t my_fun(int foo, struct SCTP_struct *bar) { statement; } Every switch statement should have a default clause. If the default can never happen, default should crash or otherwise report failure. A loop with no body looks like this: while (test()) { /* Do nothing. */ } If a compound condition or arithemetic expression extends beyond the 79 character limit, put the operators at the end of the line. E.g. if ((NULL == map->tsn_map) || (NULL == map->overflow_map) || (map->len == 0)) { ... The if/else style must follow that of K&R style, for example: if (foo) { ... } else { ... } Unrequired whitespace should be removed from the end of lines and end of file. Hardtabs should be used where possible. 5.0 Compiler and Behavior issues When comparing a constant to a variable, put the constant on the left. The compiler will tell you if you ommited a '='. E.g. if (MY_CONSTANT == var) { whatever(); } Please eliminate all compiler warnings. "Compilation errors are, in a way, unit test failures of their own. They tell us that the implementation does not match the specification." -- check.sf.net tutorial Please make forward declarations for all functions in the appropriate header files. This helps us detect interface changes. Whenever practical, allocate a large block of memory OUTSIDE a loop and then populate it inside the loop, rather than allocating many small blocks inside the loop. Do not use #ifdef TEST_FRAME unless absolutely necessary. In particular, if you simply call kernel functions which are not defined in the test frame, please add them to the test frame. The only case we know of which is difficult to handle is static inline functions. We require using this style of initialization: struct in_ifaddr eth2_ifa = {.ifa_next = NULL, .ifa_dev = NULL, .ifa_local = 0, .ifa_address = 0}; Keyword initializations are less susceptible to bugs due to changes in the underlying structures. 6.0 Version changes The lksctp-tools packages uses the "M.m.p" versioning model for both the package itself & the provided shared libraries: - (M)-ajor revision change means both source & binary incompatibility (user source code change might be required) - (m)-inor revision change means source compatibility, while ABI might not be preserved (rebuild is required) - (p)-atchlevel change means that both API & ABI are preserved. lksctp-tools-1.0.16+dfsg.orig/doc/states.txt0000644000175000017500000002672512300634451020524 0ustar michaelmichael#!enscript -G -r -f Courier7 -o states.ps - Version 0.11. Best viewed on a 176 column terminal or printed with the above command. This table shows actions in response to all possible messages in all possible states for SCTP. It is based on RFC2960. Arguments to the state functions: (asoc, {(skb, verificationTag, singleton) || (primitive_args) || nil} ) - asoc is the association in question, NULL for CLOSED - The second arg is a coproduct depending on the event -- for a chunk we have: --- skb is the inbound chunk --- verificationTag is from the SCTP header --- singleton is true if the chunk is alone in its packet -- for a primitive we have --- primitive_args is a union which captures the args to all primitives -- for other events the second argument is undefined. Return values of the state functions: (asoc, NewState, timers, responsePacket, ULPNotice, error, unique) - asoc is the association in question, NB: might be a CLOSED asoc - NewState is the next state the machine should move to - timers is new timer values, NULL if not needed - responsePacket is an outbound packet to send, NULL if not needed - ULPNotice is any response or notification we need to send to the ULP - error is an error code, NULL if there was no error - unique is a boolean that tells us if the chunk has to be alone in its packet. undef if the event was not a chunk. Most of the state functions should be self-explainatory. Here are some which might not be clear: violation - Can not happen -- the other guy is violating the protocol. other_stupid - The other implementation is doing a legal thing which is a BAD IDEA. lucky - We did something legal but stupid and got away with it :-). bug - We did something impossible. * in the left column means that this is "normal sender" flow. + in the left column means that this is "normal receiver" flow. % marks chunks which may NOT be bundled. See 3.0 and 6.10. ! marks special security considerations Count the >'s to calculate state transitions. 0 - Fixed in Version 11. 1 - If we see more INIT ACK's than we sent INIT's, we may be under hijack attack 2 - 3.3.10.10 is a special case of 5.2.4 for SHUTDOWN-ACK-SENT. 3 - 6.0 says that OUTBOUND data should only be generated in ESTABLISHED, SHUTDOWN-PENDING, and SHUTDOWN-RECEIVED. 4 - Contradiction fixed in v11. 5 - implementation specific (safe to leave unspecified) 6 - 7 - This is not explicit but is a logical consequence of other requirements. 8 - If his HEARTBEAT beats his cookie you'll send an ABORT. 9 - There is a finite probability that this orderly shutdown will turn into an ABORT. | CLOSED | COOKIE-WAIT | COOKIE-ECHOED | ESTABLISHED | SHUTDOWN-PENDING | SHUTDOWN-SENT | SHUTDOWN-RECEIVED | SHUTDOWN-ACK-SENT -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- Chunks | | | | | | | | -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- ABORT | pdiscard(8.4.2)| do_9_1_abort <|do_9_1_abort <<| do_9_1_abort <<<| do_9_1_abort >>>>| do_9_1_abort >>>| do_9_1_abort >>| do_9_1_abort > INIT %|*do_5_1B_init | do_5_2_1_siminit| do_5_2_1_siminit| do_5_2_2_dupinit | do_5_2_2_dupinit | do_5_2_2_dupinit| do_5_2_2_dupinit | do_9_2_reshut INIT ACK %| discard(5.2.3)|*do_5_1C_ack >| discard(5.2.3) 1| discard(5.2.3) 1| discard(5.2.3) 1| discard(5.2.3) 1| discard(5.2.3) 1| discard(5.2.3) 1 COOKIE ECHO |*do_5_1D_ce >>>| do_5_2_4_dupcook| do_5_2_4_dupcook| do_5_2_4_dupcook | do_5_2_4_dupcook | do_5_2_4_dupcook| do_5_2_4_dupcook | do_5_2_4_dupcook 2 COOKIE ACK | discard 4| discard(5.2.5) |*do_5_1E_ca >| discard(5.2.5) | discard(5.2.5) | discard(5.2.5) | discard(5.2.5) | discard(5.2.5) SHUTDOWN | tabort_8_4_8 | discard(9.2) 0| discard(9.2) 0|+do_9_2_shut >>>| discard(0.2) 0| do_9_2_shutack>>| discard(0.2) 0| discard(0.2) 0 SHUTDOWN ACK | do_8_4_5_shut | do_8_4_5_shut | discard 0| violation 7| violation 7|*do_9_2_final >>>| violation 7| do_9_2_final > SHUTDOWN COMPLETE %| discard(8.4.6)| discard(8.5.1c) | discard(8.5.1c) | discard(8.5.1c) | discard(8.5.1c) | discard(8.5.1c) | discard(8.5.1c) |+4(C) > DATA | tabort_8_4_8 | discard(6.0) | discard(6.0) |*eat_data_6_2 | eat_data_6_2 | eat_data_fast4-4| discard(6.0) | discard(6.0) SACK | tabort_8_4_8 | discard(6.0) | eat_sack_6_2_1 |*eat_sack_6_2_1 | eat_sack_6_2_1 | discard(6.0) | eat_sack_6_2_1 | discard(6.0) HEARTBEAT | tabort_8_4_8 | violation 7| other_stupid 8|*beat_8_3 | beat_8_3 | beat_8_3 | beat_8_3 | other_stupid 9 HEARTBEAT ACK | tabort_8_4_8 | violation 7| lucky 7|*backbeat_8_3 | backbeat_8_3 | backbeat_8_3 | backbeat_8_3 | backbeat_8_3 ERROR_stale | discard 4| discard(5.2.6) | do_5_2_6_stale | discard(5.2.6) | discard(5.2.6) | discard(5.2.6) | discard(5.2.6) | discard(5.2.6) ERROR | tabort_8_4_8 | ? | ? | ? | ? | ? | ? | ? ECNE | bug? | bug? | do_ecne | do_ecne | do_ecne | do_ecne | do_ecne | violation CWR | discard | discard | discard | do_ecn_cwr | do_ecn_cwr | do_ecn_cwr | discard | bug? -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- Timeouts | | | | | | | | -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- T1-COOKIE TO | bug | bug | do_4_3_reecho | bug | bug | bug | bug | bug T1-INIT TO | bug | do_4_2_reinit | bug | bug | bug | bug | bug | bug T2-SHUTDOWN TO | bug | bug | bug | bug | bug | do_9_2_reshut | bug | do_9_2_reshutack T3-RTX TO | bug | bug | do_6_3_3_retx | do_6_3_3_retx | do_6_3_3_retx | bug | do_6_3_3_retx | bug HEARTBEAT TO | bug | bug | bug | do_8_3_hb_err | do_8_3_hb_err | heartoff 5| do_8_3_hb_err | heartoff 5 SACK TO | bug | bug | bug | do_6_2_sack | do_6_2_sack | do_6_2_sack | bug | bug -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- Other Events | | | | | | | | -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- NO PENDING TSN | ignore | ignore | ignore | ignore |*do_9_2_start_shut >| ignore |+do_9_2_shutack 4-6>| ignore ICMP UNREACHFRAG | adjust_mtu | adjust_mtu | adjust_mtu | adjust_mtu | adjust_mtu | adjust_mtu | adjust_mtu | adjust_mtu -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- Primitives | | | | | | | | -----------------------|---------------|-----------------|-----------------|------------------|--------------------|-----------------|--------------------|------------------- PRM_INITIALIZE | | error | error | error | error | error | error | error PRM_ASSOCIATE | do_PRM_ASOC >| error | error | error | error | error | error | error PRM_SHUTDOWN | error | mark_shutdown 5| mark_shutdown 5|*do_9_2_PRM_SHUT >| discard 5| discard 5| discard(9.2) | discard 5 PRM_ABORT | error | do_PRM_ABORT <| do_PRM_ABORT <<| do_PRM_ABORT <<<| do_PRM_ABORT >>>>| do_PRM_ABORT >>>| do_PRM_ABORT >>| do_PRM_ABORT > PRM_SEND | error | do_PRM_SENDQ6.0 | do_PRM_SENDQ6.0 | do_PRM_SEND | error(9.2) | error(9.2) | error(9.2, 4-5) | error(9.2, 4-7) PRM_SETPRIMARY | error | error | do_PRM_SETPRI | do_PRM_SETPRI | do_PRM_SETPRI | do_PRM_SETPRI | do_PRM_SETPRI | do_PRM_SETPRI PRM_RECEIVE | error | error | | do_PRM_RCV | do_PRM_RCV | do_PRM_RCV | do_PRM_RCV? | do_PRM_RCV? PRM_STATUS | error | get_PRM_STATUS | get_PRM_STATUS | get_PRM_STATUS | get_PRM_STATUS | get_PRM_STATUS | get_PRM_STATUS | get_PRM_STATUS PRM_CHANGEHEARTBEAT | error | do_PRM_CH_HB | do_PRM_CH_HB | do_PRM_CH_HB | do_PRM_CH_HB | do_PRM_CH_HB | do_PRM_CH_HB | do_PRM_CH_HB PRM_REQUESTHEARTBEAT | error | do_PRM_HB | do_PRM_HB | do_PRM_HB | do_PRM_HB | do_PRM_HB | do_PRM_HB | do_PRM_HB PRM_GETSRTTREPORT | error | get_PRM_SRTT | get_PRM_SRTT | get_PRM_SRTT | get_PRM_SRTT | get_PRM_SRTT | get_PRM_SRTT | get_PRM_SRTT PRM_SETFAILURETHRESHOLD| error | error | do_PRM_FTHRESH | do_PRM_FTHRESH | do_PRM_FTHRESH | do_PRM_FTHRESH | do_PRM_FTHRESH | do_PRM_FTHRESH PRM_SETPROTOPARAMETERS | error | do_PRM_SETPARM | do_PRM_SETPARM | do_PRM_SETPARM | do_PRM_SETPARM | do_PRM_SETPARM | do_PRM_SETPARM | do_PRM_SETPARM PRM_RECEIVE_UNSENT | error | ? | ? | ? | ? | ? | ? | ? PRM_RECEIVE_UNACKED | error | ? | ? | ? | ? | ? | ? | ? PRM_DESTROY | error | do_PRM_DIEDIE | do_PRM_DIEDIE | do_PRM_DIEDIE | do_PRM_DIEDIE | do_PRM_DIEDIE | do_PRM_DIEDIE | do_PRM_DIEDIE lksctp-tools-1.0.16+dfsg.orig/doc/template.c0000644000175000017500000000353412300634451020430 0ustar michaelmichael/* SCTP kernel Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 La Monte H.P. Yarroll * * This file is part of the SCTP kernel Implementation * * $Header: /home/CVS/tsp/SCTP/sctp-tools/doc/template.c,v 1.1.1.1 2002/08/06 22:31:05 inaky Exp $ * * These functions frob the sctp nagle structure. * * 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 * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * Written or modified by: * La Monte H.P. Yarroll * * Any bugs reported given to us we will try to fix... any fixes shared will * be incorporated into the next SCTP release. */ static char *cvs_id __attribute__ ((unused)) = "$Id: template.c,v 1.1.1.1 2002/08/06 22:31:05 inaky Exp $"; #include lksctp-tools-1.0.16+dfsg.orig/doc/Makefile.am0000644000175000017500000000047412300634451020505 0ustar michaelmichaelinclude $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules internet_drafts = \ draft-ietf-tsvwg-sctpsocket-14.txt \ draft-ietf-tsvwg-addip-sctp-15.txt rfcs = rfc2960.txt rfc3309.txt rfc3257.txt rfc3286.txt rfc3758.txt \ rfc3873.txt rfc4460.txt EXTRA_DIST += $(rfcs) $(internet_drafts) lksctp-tools-1.0.16+dfsg.orig/doc/ols.tex0000644000175000017500000007711512300634451017776 0ustar michaelmichael% TEMPLATE for Usenix papers, specifically to meet requirements of % TCL97 committee. % originally a template for producing IEEE-format articles using LaTeX. % written by Matthew Ward, CS Department, Worcester Polytechnic Institute. % adapted by David Beazley for his excellent SWIG paper in Proceedings, % Tcl 96 % turned into a smartass generic template by De Clarke, with thanks to % both the above pioneers % use at your own risk. Complaints to /dev/null. % make it two column with no page numbering, default is 10 point % Munged by Fred Douglis 10/97 to separate % the .sty file from the LaTeX source template, so that people can % more easily include the .sty file into an existing document. Also % changed to more closely follow the style guidelines as represented % by the Word sample file. % This version uses the latex2e styles, not the very ancient 2.09 stuff. % adapted for Ottawa Linux Symposium \documentclass[twocolumn]{article} \usepackage{ols,epsfig} \begin{document} %Remove this next line if your system defaults correctly. \special{papersize=8.5in,11in} %don't want date printed \date{} %make title bold and 14 pt font (Latex default is non-bold, 16 pt) \title{\Large \bf Linux Kernel SCTP : The Third Transport} %for single author (just remove % characters) \author{ La~Monte H.P.\ Yarroll \\ %{\em Your Department} \\ {\em Motorola GTSS}\\ %{\em Your City, State, ZIP}\\ % is there a standard format for email/URLs?? % remember that ~ doesn't do what you expect, use \~{}. {\normalsize piggy@acm.org} \\ % % copy the following lines to add more authors \and Karl Knutson \\ {\em Motorola GTSS}\\ %% is there a standard format for email/URLs?? {\normalsize karl@athena.chicago.il.us} % } % end author \maketitle % You have to do this to suppress page numbers. Don't ask. \thispagestyle{empty} \renewcommand{\thefootnote}{\fnsymbol{footnote}} \subsection*{Abstract} % nuked italics -- FD The Stream Control Transmission Protocol (SCTP) is a reliable message-oriented protocol with transparent support for multihoming. It allows multiple independent complex exchanges which all share a single connection and congestion context. We provide an overview of the protocol, the UDP-style API and the details of the Linux kernel reference implementation. The brief API discussion is intended for developers wishing to use SCTP. The detailed implementation discussion is for developers interested in contributing to the kernel development effort. \section{Introduction} The developers at the Linux 2.5 Kernel Summit in San Jose achieved a rough consensus that 2.5 should probably support SCTP, a new transport protocol from the IETF. This paper introduces the ongoing work on such an implementation, providing some details for both the application developer and the kernel developer. The Stream Control Transmission Protocol (SCTP) is a reliable message-oriented protocol with transparent support for multihoming. It allows multiple independent complex exchanges which all share a single connection and congestion context. \subsection{History of SCTP} The SIGTRAN (Signalling Transport) Working Group of the IETF is concerned with the transport of telephony signalling data over IP. Upon reviewing the available standard transport protocols, they concluded that none of them met the transport requirements of signalling data. SIGTRAN concluded that they needed a new transport protocol which could provide reliable message delivery, tolerate network failures, and avoid the head-of-line-blocking problem. We will discuss this problem later. The WG selected a proposal from Randall Stewart and Qiaobing Xie of Motorola as a starting point. Stewart and Xie had developed a Distributed Processing Environment, Quantix, aimed at telephony applications. This DPE had been successfully demonstrated at Geneva Telecom in 1999. The Working Group took great care in constructing the new protocol, SCTP, incorporating many lessons learned from TCP, such as congestion control, selective ACK, message fragmentation and bundling. The core transport protocol from Quantix brought support for multihoming, message framing, and streams. We discuss all of these features at length later. The IESG decided that the resulting protocol was robust enough to be elevated from a specialised transport for telephony signalling to a new general purpose transport to stand beside UDP and TCP. To this end, they moved the work from SIGTRAN to TSVWG, the general transport group. As of this writing, the core specification, \cite{rfc2960}, is at Proposed Standard. There have been three successful bakeoffs covering over 25 separate implementations. Lessons learned from the most recent bakeoff are being written up in an ``Implementor's Guide'', \cite{impl}. \subsection{SCTP in the Linux kernel} Shortly before the first bakeoff, the IESG asked SIGTRAN to move SCTP from riding on UDP to riding directly on top of IP. The long term goal was clearly was to move SCTP from user space into the kernel. Aside from the obvious performance gains, this has the effect of reducing the number of implementations to roughly one per operating system. This makes it easier to verify the stability of most of the implementations which appear on the Internet. Randall Stewart saw the importance of this and started one of the authors of this paper working on a port of the user space implementation to the Linux kernel. This port was intended as a reference for developers of implementations for other kernels to examine. The Linux kernel implementation has since diverged significantly from the user space reference, but maintains the standards of a reference implementation (see Coding Standards, below). \subsection{SCTP examples} SCTP is a reliable message-oriented protocol with transparent support for multihoming. It allows multiple independent complex exchanges which all share a single connection and congestion context. Many network applications operate by exchanging simultaneously, short, similar sequences of data continuously. The traffic produced by these operations can be characterised as MICE (Multiple Independent Complex Exchanges). It is also true that many applications which use MICE also have high network reliability requirements. \subsubsection{A database app} One example is a client/server database application. Each request and each response is a message. Each transaction is a sequence of dependent request/response pairs. Implemented over TCP, this application would have to provide its own message boundaries, since TCP sends bytes, not messages. How do we implement MICE with TCP? We have two ways of doing this: multiple connections, or a single multiplexed and reused connection. With each transaction over a separate TCP connection, we gain the independence of transactions, but at a cost in performance. Since TCP (as a general purpose transport protocol) uses congestion control, each of the connections would have to go through slow-start and if most transactions were short, they would never get out of slow-start. With all transactions over a single TCP connection, we make efficient use of the network bandwidth, but open ourselves up to the head-of-line blocking problem. This means that if one segment in one transaction is lost, this blocks all transactions, not just the one with the lost segment. If we use SCTP for the same application we gain the benefits of using TCP, as well as advantages peculiar to SCTP. SCTP directly supports messages and guarantees TCP-like levels of bandwidth efficiency via bundling and fragmentation. Each database transaction can be represented as an ordered stream of messages, which are independent in SCTP for retransmission purposes. This means that while SCTP has the same congestion control mechanisms as TCP, it does not have to resort to multiple connections nor is it vulnerable to the head-of-line blocking problem. \subsubsection{A free clinic} Another example of SCTP use is for a free\footnote{Free as in ``free beer''.} clinic which needs a reliable way to use its IP-networked patient monitoring software. This has many similarities to the example above in that different monitoring devices would need to send simultaneous information---multiple independent complex exchanges. The main difference is in the higher network reliability requirements. A reasonable way to improve the network reliability is to set up a parallel network and use multihoming for the client and server applications. However, if the application is TCP-based, the multihoming needs to be added to the application. With SCTP, the multihoming ability is built into the protocol. All that is necessary is to make the appropriate socket calls and SCTP will take advantage of the addresses available in the existing network. This also applies if one side of the connection has more addresses than the other. \section{The UDP-style API} Any new protocol needs an API. In particular for an Internet protocol, it's important to have the API match the API normally used for IP networks. This is the Berkeley sockets model---the SCTP version is defined in the Internet Draft ``Sockets API Extensions for SCTP''\cite{api}. The API draft defines two complementary interfaces to SCTP--one for compatibility with older TCP-based applications, and another for new applications designed expressly to use SCTP. The Linux Kernel SCTP stack does not yet implement the former, so we discuss only the UDP-style interface. The conceptual model of the UDP-style API is (naturally) that of plain UDP. To send a message in UDP, you create a socket, bind an address to it and send your message using \texttt{sendmsg()}. To receive a message in UDP, you create a socket, bind an address to it and use \texttt{recvmsg()}. It's much the same with the UDP-style API for SCTP. To send a message, you create a socket, bind \textit{addresses} to it and use \texttt{sendmsg()}. The SCTP stack underlying the API handles association startup and shutdown automatically. The same goes for message reception. To receive a message in UDP-style, you create a socket, bind \textit{addresses} to it and use \texttt{recvmsg()}. The important API differences between UDP and UDP-style SCTP are: multihoming; ancillary data; and the option of notifications from the SCTP stack. \subsection{Multihoming and \texttt{bindx()}} There are three ways to work with multihoming with SCTP. One is to ignore multihoming and use one address. Another way is to bind all your addresses through the use of \texttt{INADDR\_ANY} or \texttt{IN6ADDR\_ANY}. This will ``associate the endpoint with the optimal subset of available local interfaces.''(Section 3.1.2, \cite{api}) The most flexible way is through the use of \texttt{sctp\_bindx()}, which allows additional addresses to be added to a socket after the first one is bound with \texttt{bind()}, but before the socket is used to transfer or receive data. The function \texttt{sctp\_bindx()} is further described in section 8.1 of \cite{api}. \subsection{Ancillary data} To use streams with the UDP-style API, you use ancillary data in the \texttt{struct~cmsghdr} part of the \texttt{struct~msghdr} argument to both \texttt{sendmsg()} and \texttt{recvmsg()}. Ancillary data is used for initialisation data (\texttt{struct~sctp\_initmsg} and for header data (\texttt{struct~sctp\_sndrcvinfo}). Ancillary data are manipulated with the macros \texttt{CMSG\_FIRSTHDR, CMSG\_NEXTHDR, CMSG\_DATA, CMSG\_SPACE, \textnormal{and} CMSG\_LEN}. These are all defined in \cite{rfc2292}. \cite{api} provides a nice example in section 5.4.2. {\tt \small \begin{verbatim} struct sctp_initmsg { uint16_t sinit_num_ostreams; uint16_t sinit_max_instreams; uint16_t sinit_max_attempts; uint16_t sinit_max_init_timeo; }; \end{verbatim} } The initialisation ancillary data sets information for starting new associations. {\tt \small \begin{verbatim} struct sctp_sndrcvinfo { uint16_t sinfo_stream; uint16_t sinfo_ssn; uint16_t sinfo_flags; uint32_t sinfo_ppid; uint32_t sinfo_context; uint8_t sinfo_dscp; sctp_assoc_t sinfo_assoc_id; }; \end{verbatim} } The header ancillary data reports information gleaned from the SCTP headers. If requested with the \texttt{SCTP\_RECVDATAIOEVNT} socket option, this ancillary data is provided with every inbound data message. There is a handy key (\texttt{sinfo\_assoc\_id}) which identifies the association for this particular message. It also provides the flags needed to implement partial delivery of very large messages. Outbound messages should include an \texttt{sctp\_sndrcvinfo} ancillary data structure to tell SCTP which SCTP stream to put this datagram into. It is also possible to set a default stream so that this ancillary data may be omitted. \subsection{Notifications} SCTP provides for the concept of optional notifications. These are messages delivered in-band about events inside the SCTP stack, such as a destination transport address failure or a new association coming up. The notifications are marked with the \texttt{MSG\_NOTIFICATION} flag in the \texttt{msg\_flags} field of the \texttt{sctp\_sendrcvinfo} ancillary data. The notification is delivered as the body of the message returned by \texttt{recvmsg()}. In \ref{notifications} we find a table of notifications. Each notification delivers its own data structure which shares the same name (lower case, naturally) as the notification type itself. The first field of every notification is a \texttt{uint16\_t} which caries the notification type. \begin{figure*}[t] \begin{center} {\tt \begin{tabular}{ l l l } \hline \textnormal{Type} & \textnormal{Socket Option} & \textnormal{Description} \\ \hline SCTP\_ASSOC\_CHANGE & SCTP\_RECVASSOCEVNT & \textnormal{Change of association} \\ SCTP\_PEER\_ADDR\_CHANGE & SCTP\_RECVADDREVNT & \textnormal{Change in status of a given address} \\ SCTP\_REMOTE\_ERROR & SCTP\_RECVPEERERR & \textnormal{An error received from a peer} \\ SCTP\_SEND\_FAILED & SCTP\_RECVSENDFAILEVNT & \textnormal{A failure to send} \\ SCTP\_SHUTDOWN\_EVENT & SCTP\_RECVDOWNEVNT & \textnormal{The reception of a \texttt{SHUTDOWN} chunk} \\ \end{tabular} } \end{center} \caption{\label{notification}Useful notifications for an SCTP socket} \end{figure*} \section{The lksctp Project} A critical factor in the success of any new IETF protocol is of course a Linux implementation. Fortunately, key personnel at Motorola recognised this and encouraged us to tackle such a project. Months later, we have a core implementation with an ever-expanding feature set. We now have significant participation from developers at IBM and Intel and the pace is picking up. \subsection{Coding standards} In addition to the usual requirements of kernel code, our code seeks to be a useful reference for people making their own kernel implementations of SCTP. If a reader has some question about how to implement a particular section of the RFC, they need only grep for the relevant text in our code and they can find an example. As much as practical, we draw names directly from the RFC. We made the state machine into an explicit table (see \ref{states} for an excerpt) with names that refer directly back to the relevant section numbers. Clarity is a compelling requirement for our code. \subsection{Extreme Programming} As the project grew and we added developers, we clearly needed some way of coordinating our work. We decided to experiment with Extreme Programming, \cite{xp}. XP is a collection of practices aimed at controlling risk in a small to medium-sized software development project. One important principle is that you should do the simplest thing that could possibly work. A second important principle is to take advantage of the fact that programmers like to code. We use a range of XP practices, but the practices which are most visible to anybody who reads or works on lksctp are the tests and the metaphors. \section{The Tests} One of the XP practices we use is code-to-the-test. XP asks, ``If testing is good, why don't we do it all the time?'' Instead of writing tests for working code, write tests first, and then write code to pass the tests. This practice leads to a large automated test suite which runs several times per day. We use three kinds of test, unit tests, test frame functional tests, and live kernel functional tests. The most basic form of test is the unit test. Unit tests exercise all the interfaces of a particular object and confirm that it behaves correctly. They also encode regression checks for fixed bugs. These tests all have names beginning with \texttt{test\_}. The second form of test is the test frame functional tests. These are the tests with names beginning with \texttt{ft\_frame\_}. These tests check for external behaviours of the system, but with a simulated kernel. The simulated kernel is very light weight and gives us very fine control over things like timing and network properties. Ideally, functional tests should be written by the customer for a system---they encode the behaviours that the customer expects. In our case, we play the role of customer on behalf of the RFC. We also use test frame functional tests to define work items for off-site development groups. The off-site group writes tests which describe the feature they intend to implement and submits those tests as a proposal. This has proven an excellent medium for describing work. The final form of test we use is the live kernel functional test. We have many fewer of these than we would like---they are difficult to run since we must install and boot a kernel to test. This is much more work than simply running \texttt{make unit\_test}. We are exploring UML as a possible way to automate our kernel functional tests. These tests have names beginning with \texttt{ft\_kern\_}. Code-to-the-test is a practice which you can introduce at any point in a project. When you first start, it seems that you are spending more time writing tests than writing code, but once you begin to have a critical mass of interacting tests you begin to see significant payoffs in both code quality and development velocity. We have had several incidents where interactions between unit tests and functional tests have uncovered complimentary masking bugs. Tests are not a substitute for understanding code---they are a mechanism for encoding that understanding to share with other developers, including future versions of yourself. You can learn nearly as much about our code by reading our tests as by reading the code itself. Lately, we have begun using functional tests to encode major bugs. These are among the best of all possible bug reports---they describe the failure precisely and tell exactly when the problem is gone. After the bugs are fixed the tests serve as part of the regression suite. \section{The Metaphors} XP projects are built around a unifying metaphor rather than an elaborate architecture. In our case, we chose two metaphors which could serve quite well for nearly any protocol development project. Our metaphors are the state machine and the smart pipe. Most readers are probably familiar with the state machine, but the smart pipe is a twist on a familiar concept. The idea behind a smart pipe\footnote{An alternate term may be ``oven''.} is that raw stuff goes in one end and cooked stuff comes out the other end. \subsection{The State Machine} The state machine in our implementation is quite literal. We have an explicit state table which keys to specific state functions which are tied directly back to parts of the RFC. The core of the state machine (found in \texttt{sctp\_do\_sm()}) is almost purely functional---only header conversions are permitted. Each state function produces a description of the side effects (in the form of a \texttt{struct~sctp\_sm\_retval}) needed to handle the particular event. A separate side effect processor, \texttt{sctp\_side\_effects()}, converts this structure into actions. Events fall into four categories. The RFC is very explicit about state transitions associated with arriving chunks. The RFC discusses transitions due to primitive requests from upper layers, but many of these are implementation dependent. The third category of events is timeouts. The final category is a catch-all for odd events like queues emptying. \begin{figure*}[t] \begin{center} {\tt \begin{tabular}{ l l l l l } \hline \textnormal{State:} & CLOSED & COOKIE-WAIT & COOKIE-ECHOED & ESTABLISHED \\ \hline \hline \textnormal{Chunks} & & & & \\ \hline INIT & do\_5\_1B\_init & do\_5\_2\_1\_siminit & do\_5\_2\_1\_siminit & do\_5\_2\_2\_dupinit \\ INIT ACK & discard(5.2.3) & do\_5\_1C\_ack & discard(5.2.3) & discard(5.2.3) \\ COOKIE ECHO & do\_5\_1D\_ce & do\_5\_2\_4\_dupcook& do\_5\_2\_4\_dupcook& do\_5\_2\_4\_dupcook \\ COOKIE ACK & discard & discard(5.2.5) & do\_5\_1E\_ca & discard(5.2.5) \\ DATA & tabort\_8\_4\_8 & discard(6.0) & discard(6.0) & eat\_data\_6\_2 \\ SACK & tabort\_8\_4\_8 & discard(6.0) & eat\_sack\_6\_2\_1 & eat\_sack\_6\_2\_1 \\ \hline \textnormal{Timeouts} & & & & \\ \hline T1-INIT TO & bug & do\_4\_2\_reinit & bug & bug \\ T3-RTX TO & bug & bug & do\_6\_3\_3\_retx & do\_6\_3\_3\_retx \\ \hline \textnormal{Primitives} & & & & \\ \hline PRM\_ASSOCIATE & do\_PRM\_ASOC & error & error & error \\ PRM\_SEND & error & do\_PRM\_SENDQ6.0 & do\_PRM\_SENDQ6.0 & do\_PRM\_SEND \\ \end{tabular} } \end{center} \caption{\label{states}Portion of SCTP state table showing association initialisation} \end{figure*} In order to create an explicit state machine, it was necessary to first create an explicit state table. The process of creating this table uncovered a few minor contradictions in one of the drafts of the RFC. These mostly involved conflicting catch-all cases. In Figure 1 we have an excerpt which shows the state functions involved in initialising a new association. \subsection{The Smart Pipes} Each smart pipe has one or more structures which define its internal data, and a set of functions which define its external interactions. In this respect these smart pipes can be considered a type of object, in the OO sense. All of these definitions can be found in the include file \texttt{}. Most of our smart pipes have push inputs---external objects explictly put things in by calling methods directly. A pull input is possible---the smart pipe would need to have a way to register a callback function which can fetch more input in response to some other stimulus. Some of our pipes use pull outputs. E.g. \texttt{SCTP\_ULPqueue} passes data and notifications up the protocol stack through explicit calls to the socket functions, usually \texttt{readmsg(2)}. Some of our smart pipes use push outputs. E.g. \texttt{SCTP\_outqueue} has a set of callback functions which it invokes when it needs to send chunks out toward the wire. There are four smart pipes in lksctp. They are \texttt{SCTP\_inqueue}, \texttt{SCTP\_ULPqueue}, \texttt{SCTP\_outqueue}, and \texttt{SCTP\_packet}. The first two carry information up the stack from the wire to the user; the second two carry information back down the stack. \subsubsection{\texttt{SCTP\_inqueue}} \texttt{SCTP\_inqueue} accepts packets and provides chunks. It is responsible for reassembling fragments, unbundling, tracking received TSN's for acknowledgement, and managing rwnd for congestion control. There is an \texttt{SCTP\_inqueue} for each endpoint (to handle chunks not related to a specific association) and one for each association. The function \texttt{sctp\_v4\_rcv()} (which is the receiving function for SCTP registered with IPv4) calls \texttt{sctp\_push\_inqueue()} to push packets into the input queue for the appropriate association or endpoint. The function \texttt{sctp\_push\_inqueue()} schedules either \texttt{sctp\_bh\_rcv\_asoc()} or \texttt{sctp\_bh\_rcv\_ep()} on the immediate queue to complete delivery. These functions call \texttt{sctp\_pop\_inqueue()} to pull data out of the \texttt{SCTP\_inqueue}. This function does most of the work for this smart pipe. The functions \texttt{sctp\_bh\_rcv\_ep()} and \texttt{sctp\_bh\_rcv\_asoc()} run the state machine on incoming chunks. Among many other side effects, the state machine can generate events for an upper-layer-protocol (ULP), and/or chunks to go back out on the wire. \subsubsection{\texttt{SCTP\_ULPqueue}} \texttt{SCTP\_ULPqueue} is the smart pipe which accepts events (either user data messages or notifications) from the state machine and delivers them to the ULP through the sockets layer. It is responsible for delivering streams of messages in order. There is one \texttt{SCTP\_ULPqueue} for every endpoint, but this is likely to change at some point to one \texttt{SCTP\_ULPqueue} for each socket. This smart pipe uses a data structure distributed between the \texttt{struct~SCTP\_endpoint} and the \texttt{struct~SCTP\_association}. The state machine, \texttt{sctp\_do\_sm()}, pushes data into an \texttt{SCTP\_ULPqueue} by calling \texttt{sctp\_push\_chunk\_ULPqueue()}. It pushes notifications with \texttt{sctp\_push\_event\_ULPqueue()}. The sockets layer extracts events from an \texttt{SCTP\_ULPqueue} with \texttt{sctp\_pop\_ULPqueue()}. \subsubsection{\texttt{SCTP\_outqueue}} \texttt{SCTP\_outqueue} is responsible for bundling logic, transport selection, outbound congestion control, fragmentation, and any necessary data queueing. It knows whether or not data can go out onto the wire yet. With one exception noted below, every outbound chunk goes through an \texttt{SCTP\_outqueue} attached to an association. The state machine injects chunks into an \texttt{SCTP\_outqueue} with \texttt{sctp\_push\_outqueue()}. They automatically push out the other end through a small set of callbacks which are normally attached to an \texttt{SCTP\_packet}. The state machine is capable of putting a fully-formed packet directly on the wire. At this point only \texttt{ABORT} uses this feature. It is likely that we will refactor \texttt{INIT ACK} generation again to use this feature. \subsubsection{\texttt{SCTP\_packet}} An \texttt{SCTP\_packet} is a lazy packet transmitter associated with a specific transport. The upper layer pushes data into the packet, usually with \texttt{sctp\_transmit\_chunk()}. The packet blindly bundles the chunks. If the it fills (hits the PMTU for its transport), it transmits the packet to make room for the new chunk. \texttt{SCTP\_packet} rejects packets which need fragmenting. It is possible to force a packet to transmit immediately with \texttt{sctp\_transmit\_packet()}. \texttt{SCTP\_packet} tracks the congestion counters, but handles none of the congestion logic. \section{More Data Structures} Not everything is a state table or a smart pipe---after all, this is the kernel and we ARE programming in C. Here again, we have followed the RFC very closely. Most of the key concepts in the RFC manifest themselves as explicit data structures. For convenience, we refer to these data structures as ``nouns''. Nearly all of the ``noun'' structures are designed for use with the \texttt{sk\_buff} macros for list manipulation. These macros provide a doubly-linked list with locking. \subsection{\texttt{struct~SCTP\_proto}} The entire lksctp universe is grounded in an instance of \texttt{ struct~SCTP\_proto} accessible through \texttt{sctp\_get\_protocol()}. This structure holds system-wide defaults for things like the maximum number of permitted retransmissions. It contains a list of all endpoints on the system. \subsection{\texttt{struct~SCTP\_endpoint}} Each UDP-style SCTP socket has an endpoint, represented as a \texttt{struct~SCTP\_endpoint}. Once we implement high-bandwidth sockets and TCP-style sockets, it will be possible for multiple sockets to share a single endpoint structure. The endpoint structure contains a local SCTP socket number and a list of local IP addresses. These two items define the endpoint uniquely. In addition to endpoint-wide default values and statistics, the endpoint maintains a list of associations. \subsection{\texttt{struct~SCTP\_association}} Each association structure, \texttt{struct~SCTP\_association}) is defined by a local endpoint (a pointer to a \texttt{struct~SCTP\_endpoint}), and a remote endpoint (an SCTP port number and a list of transport addresses). This is one of the most complicated structures in the implementation as it includes a great deal of information mandated by the RFC. Among many other things, this structure holds the state of the state machine. The list of transport addresses for the remote endpoint is more elaborate than the simple list of IP addresses in the local endpoint data structure since SCTP needs to maintain congestion information about each of the remote transport addresses. \subsection{\texttt{struct~SCTP\_transport}} A \texttt{struct~SCTP\_transport} is defined by a remote SCTP port number and an IP address. The structure holds congestion and reachability information for the given address. This is also where we get the list of functions to call to manipulate the specific address family. For TCP you would find this information way up in the socket, but this is not possible for SCTP. \subsection{\texttt{struct~SCTP\_chunk}} Possibly the most fundamental data structure in lksctp is \texttt{struct~SCTP\_chunk}. This holds SCTP chunks both inbound and outbound. It is essentially an extension to \texttt{struct~sk\_buff}. It adds pointers to the various possible SCTP subheaders and a few flags needed specifically for SCTP. One strict convention is that \texttt{chunk->skb->data} is the demarcation line between headers in network byte order and headers in host byte order. All outbound chunks are ALWAYS in network byte order. The first function which needs a field from an inbound chunk converts that full header to host byte order {\it in situ}. \section{Acknowledgements} The authors are members of a team at Motorola dedicated to producing open source implementations in support of IETF standardisation. We would like to thank the people who make these efforts possible, specifically Maureen~Govern, Stephen~Spear, Qiaobing~Xie, and Irfan~Ali. We are of course deeply indebted to Randall Stewart and Qiaobing Xie for having created SCTP and for starting the Linux Kernel SCTP Implementation Project. We wish to recognizee the ongoing and significant contributions from developers outside Motorola, especially Jon Grimm and Daisy Chang of IBM, and Xingang Guo of Intel. \section{Availability} All the code discussed in this paper is available from the lksctp project on Source Forge: \begin{center} \texttt{http://sourceforge.net/projects/lksctp/} \end{center} \begin{thebibliography}{2001} \bibitem[RFC2960]{rfc2960} R.~Stewart, Q.~Xie, K.~Morneault, C.~Sharp, H.~J.~Schwarzbauer, T.~Taylor, I.~Rytina, M.~Kalla, L.~Zhang, and, V.~Paxson, {\em Stream Control Transmission Protocol}, RFC~2960 (Oct~2000). \bibitem[SCTPAPI]{api} R.~Stewart, Q.~Xie, L.~H.~P.~Yarroll, J.~Wood, K.~Poon, K.~Fujita., {\em Sockets API Extensions for SCTP}, Work In Progress, \texttt{draft-ietf-tsvwg-sctpsocket-00.txt} (Jun~2001). \bibitem[SCTPIMPL]{impl} R.~Stewart. {\it et al}, {\em SCTP Implementor's Guide}, Work In Progress, \texttt{draft-ietf-tsvwg-sctpimpguide-00.txt} (Jun~2001). \bibitem[SCTPMIB]{mib} J.~Pastor, M.~Belinchon. {\em Stream Control Transmission Protocol Management Information Base using SMIv2}, Work In Progress, \texttt{draft-ietf-sigtran-sctp-mib-03.txt} (Feb~2001). \bibitem[XP]{xp} K.~Beck. {\em Extreme Programming Explained: Embrace Change}, Addison-Wesley Publishers (2000). \bibitem[SCTPORG]{sctporg}{\em Randall Stewart's SCTP site},\\ \texttt{http://www.sctp.org}, (2001). \bibitem[SCTPDE]{sctpde}{\em T\"uxen/Jungmeier SCTP site},\\ \texttt{http://www.sctp.de}, (2001). \end{thebibliography} \end{document} lksctp-tools-1.0.16+dfsg.orig/doc/what_we_were_doing.txt0000644000175000017500000010240712300634451023051 0ustar michaelmichaelWhat were we doing when we stopped? funtest1.c test_sendto() Wed Sep 27 12:48:34 CDT 2000 We are about to write sctp_do_prm_asoc(). Thu Sep 28 15:58:27 CDT 2000 DONE test_run_network() Thu Sep 28 21:37:51 CDT 2000 We are testing. The first chunk we see in outqueue has a chunkID of 0 (DATA), not 1 (INIT). It also has a length of 0. It looks like a dummy chunk. Next thing will be struct SCTP_inqueue. We WILL produce an automated test for that structure! Fri Sep 29 19:41:21 CDT 2000 We fixed the bug mentioned above. We have created a unit test for SCTP_inqueue. Next, we should implement SCTP_inqueue. Mon Oct 2 11:03:10 CDT 2000 Mon Oct 2 18:07:14 CDT 2000 Finishing up on test_inqueue. Currently giving bad results for the chunk header for the second chunk popped. Also need to clean up validate_queue's type-casting to make the warning go away. Wed Oct 4 10:51:55 CDT 2000 We have fixed the warning. Still working on the 2nd chunk. Wed Oct 4 14:06:21 CDT 2000 We passed our first automated unit test!!! sctp_bundle_out() needs writing. Wed Oct 4 16:36:10 CDT 2000 writing sctp_bundle_out() writing ip_queue_xmit() trying to find out how to call sctp_v4_rcv() Thu Oct 5 18:40:49 CDT 2000 We believe that ip_queue_xmit() is "written". We think sctp_bundle_out() is written. We are stepping through test_run_network(),sctp_v4_rcv() We have made it out to ep_put(), near the end of sctp_v4_rcv(). bh_[un]lock_ep(), ep_put() need writing. We plan to continue through sctp_v4_rcv(). GOAL: return from test_run_network() by COB Friday Fri Oct 6 18:29:01 CDT 2000 Gee! We are calling ourselves forever! We need to break this cycle by implementing bottom half/top half... Welcome to the kernel! On the upside, we made it back up into do_5_1B_init(). Fix the BUG BUG BUG at the end of ip_queue_xmit(). Mon Oct 9 12:17:59 CDT 2000 We believe test_run_network() is written--we have completed on full loop. Here is what we expect in the next three iterations: Next loop: ep2: send the INIT_ACK ep1->asoc: process the INIT_ACK, enter COOKIE_ECHOED, queue COOKIE_ECHO ueber-next loop: ep1->asoc: send the COOKIE_ECHO, send the DATA ep2->asoc: process COOKIE_ECHO, make asoc in ESTABLISHED, queue COOKIE_ACK process DATA, queue SACK ueber^2-next loop: ep2->asoc: send COOKIE_ACK, SACK ep1->asoc: process COOKIE_ACK, enter ESTABLISHED, process SACK, free DATA Mon Oct 9 18:53:44 CDT 2000 The test for SCTP_outqueue now fails! Yay! Mon Oct 9 20:41:36 CDT 2000 The test for SCTP_outqueue now passes! Yay! Goal for tomorrow: Return from test_run_network(). Continue through the loop... The DATA packet is ending up in the endpoint queue, not the assoication queue. Tue Oct 10 15:26:54 CDT 2000 Fixed. This is correct behaviour, but now we look for the association AGAIN. The TSN is not getting set. This should happen in the SCTP_outqueue. Tue Oct 10 15:55:27 CDT 2000 Added a test to test_outqueue for TSN fix. Yay, test_outqueue fails! Added a test to test_inqueue for the end-of-packet callback feature. Tue Oct 10 17:32:53 CDT 2000 Passing test... We are now using the feature in sideeffects.c. Are we getting a SACK now? Tue Oct 10 18:58:25 CDT 2000 Yes! We ARE getting a SACK! Yahoo! Plan for tomorrow: sctp_recvmsg(), sctp_send_up(). This is probably a new data struture... Wed Oct 11 14:21:32 CDT 2000 Yes, it is several... 7? Sigh. Yay! test_ULPqueue fails! Wed Oct 11 16:56:06 CDT 2000 DANGER, WILL ROBINSON! NOT ALL UNIT TEST PASS! But the day is over and piggy needs to leave... WRITE sctp_ULPqueue.c:sctp_ULP_chunk2event() Thu Oct 12 12:08:23 CDT 2000 Put SCTP and IP headers on the test chunk. Make sure that skb->data, however, points at the actual payload. Thu Oct 12 15:40:00 CDT 2000 test_ULPqueue passes! Yahoo! Back to funtest1... options for things that changed which might corrupt the MD5digest: do_gettimeofday() replaced get_time() tv_add() replaced net_profile_add() get_random_bytes() replaced net_random() I switched to MD5 and the problem disappeared. This is very bad. The problem is that the SLA1 code is overruning the stack and creaming its parent's variables. Specifically, context->howManyInBlock is getting above 64 (the size of the block). This causes "leftToFill" to become negative at line 195 and then things really fall apart. This looks like a bug to me, but it worked before... Fri Oct 13 10:14:37 CDT 2000 Goal for today: Get through ueber^2-next loop. Don't forget to look for that COOKIE ACK... Fri Oct 13 16:52:11 CDT 2000 We have delivered a data packet all the way to the user from the other user! We do not seem to have either a COOKIE_ACK OR a SACK. Such is life... More to do... We do not deliver the COMUP event either... We sort of deliver the COMMUNICATION_UP message. What a WASTE. We REALLY need to get back to COOKIE_ACK/SACK. By early next week we MUST be all the way to SHUTDOWN_ACK. Mon Oct 16 12:19:18 CDT 2000 We DID see that COOKIE_ACK/SACK. We have received three packets. Check to make sure we got the second SACK. Goal for today: Generate a SHUTDOWN. This means a new event type for the state machine: OTHER. Mon Oct 16 15:11:16 CDT 2000 We have finished sctp_close(). Mon Oct 16 20:52:42 CDT 2000 We got a SHUTDOWN processed. The NO PENDING TSN event needs to be scheduled so that it happens AFTER all the side effects for the PRIOR event. Refactor the SACK processing OUT of sctp_outqueue.c--use the empty handler. REMEMBER TO WRITE THE TEST FIRST! Once all that works, continue on to generating SHUTDOWN ACK. Goal for tomorrow: pass empty handler test, get back to the point in the functional test where we are ready to generate SHUTDOWN ACK. Stretch goal for tomorrow: Get to the end of the functional test. Tue Oct 17 11:39:00 CDT 2000 We added sctp_delayed_side_effects() where we can execute side effects which MUST happen after all other side effects are processed. The test for the empty queue feature now fails! Tue Oct 17 11:54:51 CDT 2000 The test for the empty queue feature now passes! We have decided to put this off until post-Bakeoff: Refactor the SACK processing OUT of sctp_outqueue.c--use the empty handler. REMEMBER TO WRITE THE TEST FIRST! P.S. We DO use the empty handler now, but SACK processing is still partially embedded in outqueue. DONE: sctp_do_9_2_final() should generate an event to send to the ULP... DONE: We need to deal with the possibility of an association unlinking in the middle of an SK_FOR. If there are undelivered notifications in association, delay its freedom. Tue Oct 17 18:17:07 CDT 2000 We completed the full protocol negotiation in funtest1.c! Yahoo! DONE: All that remains is to keep the association around long enough to deliver the final notification. DONE: Also, sctp_do_4_C needs to generate a ULP event too... The three major tools... No, four... Goal for tomorrow: 1) Running functional test by lunch time. 2) Make the kernel link. Wed Oct 18 10:42:40 CDT 2000 We now set the destination address correctly. (We think...) Wed Oct 18 12:42:05 CDT 2000 The unit tests run again. Setting destination addresses broke a couple of them... Wed Oct 18 14:45:26 CDT 2000 Yeehaw! The functional test passes! Wed Oct 18 15:23:26 CDT 2000 The kernel links! Tasks: Write a kernel functional test. Make it fail. Write sctp_sendmsg(). Register all the SCTP structs in the right places... Move funtest1.c:test_run_network functionality into the kernel. Wed Oct 18 16:44:30 CDT 2000 funtest2 now fails! Yay! It features cool error messages... goals for tomorrow: DONE: 1) Write sctp_sendmsg(). DONE: 2) Register all the SCTP structs in the right places... Thu Oct 19 12:09:43 CDT 2000 We have a first draft of sctp_sendmsg(). DONE: Write lower level functions for sctp_sendmsg(). DONE: Fix the retval misuses in sctp_recvmsg(). DONE: Check all of sctp_socket.c for user space memory references. Thu Oct 19 18:10:27 CDT 2000 FIXED: We are failing to generate SACKS. It appears that pop_inqueue is deciding that eop is not happening for data chunks. Thu Oct 19 21:32:36 CDT 2000 It appears that at least the three key structures (sctp_prot, sctp_protocol, and inet_seqpacket_ops) are properly registered. We also sort of fixed a problem with queue_xmit--it needs to be transport specific. We still do not set it properly in the transport structure, but as a hack, we steal it from the ep. goals for Friday: 1) Move funtest1.c:test_run_network functionality into the kernel. 2) Have a real kernel panic! 3) Move the repository onto one of the laptops... Fri Oct 20 18:23:43 CDT 2000 test_inqueue now fails after changing handler handling (i.e. item 1 above)! Fri Oct 20 18:39:30 CDT 2000 test_inqueue now passes! (as do test_outqueue & test_ULPqueue) funtest1, anyone? We refactored to get rid of sctp_sm_delayed_sideeffects(). This led to outqueue empty processing getting a LOT cleaner. This also forced us to fix the empty test in test_outqueue and feed it a REAL(ish) SACK. This led us in turn to a VERY subtle TSN bug. XP RULES! YOW YOW YOW!!!! Fri Oct 20 23:28:57 CDT 2000 We passed the functional test and all the unit tests. We think we have something we MIGHT be able to link into a kernel and test... 3) Move the repository onto one of the laptops... Goal for Monday: 2) Have a real kernel panic! Tue Oct 24 16:10:44 CDT 2000 Still no kernel panic, but we have some things which seem to work! Yowza! Specifically, sctp_socket(), and sctp_bind() appear to work. We get an -EFAULT when we call sctp_sendmsg(). In sctp_recvmsg() we had a hang. Tue Oct 24 16:57:05 CDT 2000 unit tests pass (again)! Yahoo! Wed Oct 25 10:57:59 CDT 2000 funtest3 rewritten to use getopt and support addresses other than the loopback. Wed Oct 25 11:47:18 CDT 2000 funtest3 --listen fails! Thu Oct 26 00:18:43 GMT-6 2000 Why are we getting EINVAL? - We are certain that the address going to bind is in kernel space. - Add the endpoint port--we wish to differentiate the two possible failures. Wed Oct 25 16:38:56 CDT 2000 We are setting the peer's port to network byte order in one or both of the following: sctp_create_asoc(), sctp_add_transport(). We are trying to make funtest1 pass again... We are trying to not panic in funtest3 --listen. Thu Oct 26 14:23:08 CDT 2000 Created the macro DEBUG_PRINT() and a matching unit test (foolishly put in funtest1.c...). It failed! It passes! By the end of the day we completed a full INIT-DATA-SHUTDOWN sequence with the user space refimpl! We listened and the usref initiated. Fri Oct 27 08:46:41 CDT 2000 Goal for today: Do the equivalent of funtest2 with funtest3 (interoperate both directions with the usref). Fri Oct 27 10:13:39 CDT 2000 funtest3 --send fails! Tue Jan 16 01:54:34 CST 2001 We have two bugs: 1) Line 277 in sctp_endpointola.c. 2) We need to handle non-existent ep properly, almost everywhere. We need to add a blow-away-the-endpoint test to one of the functional tests. Wed Jan 17 02:19:18 CST 2001 We fixed bug 1, and now cherish bug 2 wholeheartedly. We don't (?) need a blow-away-ep test, but we eventually need to work on the out-of-the-blue-packet story. We now pass funtest1 and funtest1b (Yeah!). Next up: funtest3 with back to back associating, and (dare we hope?) funtest2. (Note: _No_ _work_ will be done to fix funtest2 until after the Developers' Release.) Tue Jan 30 16:00:26 CST 2001 We have a simple-minded merge of our SCTP changes into 2.4.1. This merely resolved the conflicts--tag 'linux-2_4_1+sctp' will NOT compile. We need to do all the data structure changes. Tue Feb 27 20:07:52 CST 2001 In the middle of getting funtest1 to work (again), test_print_message prints a bad type for a message. May be a related CORE_DUMP in there somewhere too... Fri Mar 2 20:50:22 CST 2001 We believe that sctp_flush_outqueue is pretty-much ready except for starting the timers. We need to stop the timers in need to generate the timeouts ( 6.3.2 R2 tells us to turn off T3-rtx when we get acks for all data on an address... We REALLY want a per-transport transmitted queue. What we want to do is a outqueue-private component of the transport data structure. DONE: PLAN FOR MONDAY: Make a release w/o lost_data packet. PLAN FOR Wednesday after next: Release including lost data packet and whatever else we jam in... DONE: Write a unit test for bundling. Pass the unit test for bundling. Make the transmitted queues transport based because we need a per transport timer which gets turned off when there is nothing in flight. Make ft_frame_lostpacket pass. Tue Mar 13 19:44:27 CST 2001 We are working on getting test_outqueue to work again, this time with bundling. The code compiles, but still dumps core. It looks like a bug in the test frame (q->asoc is NULL). Wed Mar 14 14:07:51 CST 2001 The unit tests (including the bundling mods for test_outqueue) pass. The mods were to comment out sock_hold in the set_owner..., since it kept landing us in the real kernel code (asm/atomic.h). We thought this was due to string.h, but that gets called in somewhere magically too. Final mod was an if around the last sctp_transmit_packet for when the payload size isn't > 0. I (KK) added a catcher for payload_size < 0. Now on to making the transmitted queues transport based.(?) Wed Mar 14 16:26:59 CST 2001 Have added transmitted (not private) to SCTP_transport and initted in sctp_add_transport(). Next would be sctp_flush_outqueue(). Thu Mar 15 19:15:24 CST 2001 Whew. We added transport-transmitted to sctp_empty_outqueue(), sctp_flush_outqueue() and sack_outqueue(). We also took the check-transmitted-queue logic out of sctp_sack_outqueue() and added sctp_check_transmitted(). We also isolated a wacky SK_FOR behavior that had us stumped for a while. If you pass a local variable to SK_FOR as the_list, it has trouble ending the for loop since the local variable is on the stack (for the calling function), but the end iteration for the for"ing" (the real the_list) would be whereever it was before being copied into the local variable. Anyhow, the unit tests pass (although we haven't committed yet.) Fri Mar 16 19:19:01 CST 2001 We fixed a padding problem with the bundling code (and its attendant problems with the ULPqueue/recvmsg code). The unit tests and all ft_frame tests (except lostpacket, naturally) pass! Have not run ft_kernel_basic yet. Despite this, I'm committing, since La Monte and I(KK) will be at the IETF next week. I also need to remember to put Perry's name in the code he's worked on. Mon Mar 19 17:31:37 CST 2001 We were creating a new kind of smart pipe, the SCTP_packet. Stuff packets in the top until they transmit. Tue Mar 27 11:26:26 CST 2001 Write the unit test for SCTP_packet. Fri Apr 6 01:18:32 CDT 2001 We THINK we have a full implementation of the sockets protocol table. We will have a go at integrating af[6]_inet.c into our test frame so we can write tests for it... Tue Apr 10 11:39:13 CDT 2001 Finish SCTP_packet today. Tue Apr 10 21:39:25 CDT 2001 Yeah, right. OK, we're in the middle of transforming transmitted_queue and sacked_queue into struct list_head's so that we can avoid copying chunks when putting them in packets. What remains: DONE: Make test_outqueue compile. UNDONE: Make test_outqueue fail. DONE: Finish transforming SCTP_outqueue to the new interfaces. DONE: Make test_outqueue pass. DONE: Make test_packet compile. DONE: Make test_packet fail. DONE: Write SCTP_packet (sctp_output.c). DONE: Make test_packet pass. DOING: Get on with lost packet. Wed Apr 11 16:38:52 CDT 2001 Yay! We have test_outqueue passing... Thu Apr 12 10:23:01 CDT 2001 Goal for today: Make test_packet compile and fail. Do an intermediate commit. Thu Apr 12 16:56:53 CDT 2001 We hit our goal for the day! We've just finished the horrible table in sctp_append_chunk(). We need to write sctp_transmit_packet(). Mon Apr 16 10:39:27 CDT 2001 DONE: Goal for the day: Get all unit tests to pass (test_packet being the current red-headed-stepchild.) Mon Apr 16 15:36:42 CDT 2001 Yay! We've hit today's goal! Mon Apr 16 17:22:44 CDT 2001 Milestone: all ft_frame passes except lostpacket (Almost out of the refactoring quagmire...). Mon Apr 16 19:12:37 CDT 2001 Milestone: ft_frame_lostpacket now fails (after being rewritten a bit). SKIPPED: Fix up the statefun retval to communicate timer updates properly. DONE: Start the rtx timer. DONE: Make sure the rtx timer set/clear events are generated by the appropriate state functions. DONE: Create the rtx timeout state function. Update the side effects to: SKIPPED: Process rtx timer updates. DONE: Move chunks from transmitted to retransmit. DONE: Call flush with rtx_timeout set. Plan for tomorrow: DONE: Create the timeout event. DONE: Make ft_frame_lostpacket pass. DONE: Run ft_kernel_basic, make it pass. DONE: Run sctp_darn tests. (They failed, though...) Tue Apr 17 17:27:15 CDT 2001 ft_frame_lostpacket passes! Yeeha! Tue Apr 17 19:01:22 CDT 2001 ft_kernel_basic passes--insignificant changes needed for compilation. Wed Apr 18 14:58:30 CDT 2001 DONE: Write ft_frame_evenpackets. DONE: Have it compile and fail. DONE: Write sack timer support code. DONE: Have it compile and succeed. Wed Apr 18 16:36:17 CDT 2001 We did a small refactoring where we changed most instances of struct timeval into jiffies. We can't do this for every struct timeval since sk->stamp is a struct timeval and we use this to check cookie lifetimes. C'est la vie. So geht es in Leben. ft_frame_evenpackets fails! Yeeha! All unit tests pass! Thu Apr 19 10:34:04 CDT 2001 Goal for morning: ft_frame_evenpackets passes. To make it pass, the sack timer should be: DONE: - initialized DONE: - started DONE: - stopped DONE: - event (expiration) DONE: - state function DONE: - sctp_do_timerWork Thu Apr 19 13:17:08 CDT 2001 We've written the sack timer code and it compiles, but the ft still fails. Thu Apr 19 15:39:58 CDT 2001 ft_frame_evenpackets passes! Yay! What we need to do for multihoming: DONE: Extend test frame for multilink. Write ft_frame_lostlink. Make ft_frame_lostlink compile. Make ft_frame_lostlink fail. Write multi-homing support: - Add counter events to OTHER table - Stroke error counts (8.2) DONE: - Write sctp_bindx() (API 8.1) - Clear error counter when RTX timer is stopped. (8.2) - Do failover state function (8.2, 6.4.1) - Do failover side effects - Change sctp_transmit_packet() to modify the socket for the chosen destination address. - Change transport selection to skip inactive destinations (bakeoff 3.6) Make ft_frame_lostlink pass. Thu Apr 19 23:01:11 CDT 2001 We need to refactor the whole INIT/INIT ACK/COOKIE ECHO startup sequence to make the INIT header processing more symmetric. In particular, we are going to put the whole INIT chunk (with all parameters) into the cookie and simplify the cookie as much as possible. This allows both sides to take a skeletal association and an INIT packet and build a full association. Check whether the initial destination address needs to be automagically added to the list of IP addresses for the association. Fri Apr 20 17:28:42 CDT 2001 We're in the middle of the aforementioned refactoring. We are working our way through the function do_5_1B_init(). Credo that sctp_make_temp_asoc() is now properly rewritten. Next to rewrite is sctp_make_init_ack(). tar up THIS directory heirarchy copy to both laptops check out the most recent CVS'd stuff on both laptops Sat Apr 21 18:31:28 CDT 2001 I'm in the middle of sctp_unpack_cookie(). Make sure that everything lines up properly... I THINK the static parts of the INIT are still unaccounted for. Maybe. Maybe not... No, I think those are part of asoc->c, in which case, they are properly handled. Check that we do all three passes through the variable-length parameters: INIT, INIT ACK, COOKIE ECHO (INIT is in the cookie). Sun Apr 22 01:46:21 CDT 2001 See the FIX ME in sctp_unpack_cookie(); Tue Apr 24 16:43:30 CEST 2001 sctp_make_cookie_echo() in sctp_side_effects() returns a malformed chunk. Thu Apr 26 10:44:15 CEST 2001 We have a buildable kernel and we pass all unit and functional tests except ft_frame_lostlink. ft_kernel_basic remains untested. The plan for today is to get some interop test run with Sun and perhaps some others... Thu Apr 26 18:36:54 CEST 2001 We have a deadly INIT packet from Sun. We are trying to make a test frame from the deadly packet. Added WORD_ROUND() to sctp_addto_chunk() to support correct parameter bounding... Added some infrastructure to support replacing arbitrary packets in a transaction. This doesn't work yet and isn't quite as flexible as we really want. Fri Apr 27 11:34:22 CEST 2001 Start the SSN at 0, not 1. Increment the SSN. Tue May 1 16:11:17 CDT 2001 These are the changes that piggy made on the airplane from Nice: DONE: Do duplicate checking in sctp_bind_endpoint(). DONE: Add struct bare_ip_sctp_packet. DONE: Modify CHUNK_TYPE() so that it can work even if an IP header is present. DONE: Fix the calls to CHUNK_TYPE(). The first call is on an IP packet with a header. Wed May 9 15:39:23 CDT 2001 Implement Jon Grimm's suggestion about sctp_init(). DONE: 1. Take the sctp_proto_initted check out of sctp_get_protocol(). DONE: 2. Call module_init(sctp_init) at the end of sctp_protocol.c (Less random, but more thoughtful, placement.) DONE: 3. Modify the frame tests to call sctp_init() directly. DONE: 4. Test the simulated daylights out of it. UNDONE: 5. Test the living daylights out of it. Wed May 9 16:41:47 CDT 2001 DONE: Include from sctpConstants.h. DONE: Go through sctpConstants.h looking for stuff needed by the user and moving it to sys/sctp.h. DONE: Go through sctpEvent.h looking for stuff needed by the user and moving it to sys/sctp.h. DONE: Test the simulated daylights out of it. DONE: Test the living daylights out of it. Thu May 10 11:55:57 CDT 2001 We moved kernel/include/sys/sctp.h to linux/include/linux/sctp.h. The kernel does NOT have an include/sys/ directory, and include/linux/tcp.h has sortof similar semantics... Move linux/include/linux/sctp.h to kernel/include/net/sctp/sctp_user.h and copy THAT to kernel/usr_include/netinet/sctp.h. Thu May 10 16:34:35 CDT 2001 Here are all the horrible places we need to put "132": DONE: /usr/include/linux/socket.h DONE: /usr/include/linux/in.h DONE: /usr/include/netinet/in.h These are all in kernel/usr_include and kernel/Makefile has been modified appropriately. DONE:Tomorrow: Describe the hijack attack in detail in an email message to Randy and Qiaobing. Fri May 11 15:43:46 CDT 2001 Next possible tricks are to work up tests for the SACK processing/RTX work, the spicy INIT, or ft_frame_lostlink. We will extend ft_frame_lostpacket to include multiple lost packets and we will have it check reordering. Wed May 16 14:50:29 CDT 2001 First pass priority list: Develop tests for these bugs encountered at the 3rd bakeoff. (For Wednesday, go for the low hanging fruit.) BUG: We ignore ABORT. TRACE: compaq3_paddedinitackOK.tcp TEST: ft_frame_abort BUG: We will send extra data before we get a COOKIE ACK... TRACE: datakinectics_2 We really lucked out and this implementation ran fine... TEST: BUG: We have an INIT that causes an oops. TRACE: sun (lost trace) TEST: ft_frame_init_bomb BUG: This INIT ACK causes an oops. TRACE: telesoft2_lostsendings.tcp, telesoft3_spicyinitack.tcp TEST: BUG: We don't gap ACK. BUG: We retransmitted a TSN which they had gap ack'd. TRACE: datakinectics_3, ulticom_3 TEST: BUG: We produce MANY SACK's in a row. Bleah. This isn't officially a bug. Is it legal for us to look ahead in our input buffer? Well, Stevens thinks that this is correct behaviour. We should NOT look ahead in our input buffer. TRACE: adax2_goodsend.tcp TEST: no test needed BUG: We did not bundle retransmissions. TRACE: adax2_goodsend.tcp TEST: Mon May 21 15:56:47 CDT 2001 Today and Tuesday are SCTP days. (Like Crazy Days, only more SCTP and less street fair.) Write the ABORT test. Tue May 22 18:49:51 CDT 2001 Once again, we are changing the end-of-packet handling to solve some nasty problem. There are two issues here: FIXED: - sctp_tq_sideeffects is global and very dangerous (i.e. wrong) FIXED: - sctp_gen_sack can be called on an aborted association--it still has a pointer to the free'd memory... Solution: We are marking the last chunk in a packet as the final chunk. DONE: - Add the eop flag to SCTP_chunk. DONE: - Set the eop flag for the final chunk (sctp_pop_inqueue()). DONE: - Initialize the eop flag when we create a new chunk (sctp_chunkify()). DONE: - Add gensack to the retval structure. DONE: - Modify the data state function to set retval->gensack if eop is set. DONE: - Set up gensack side effect. DONE: - Fix up the prototype for sctp_gen_sack(). DONE: - Create asoc->sack_needed. DONE: - Dispose of asoc->peer.dataSeen DONE: - Dispose of asoc->counters[SctpCounterAckState] DONE: - Dispose of chunk->counted DONE? - Dispose of sctp_tq_sideeffects and friends. DONE: -- call sctp_other_no_pending_TSN() from sctp_side_effects(). DONE: -- eliminate handlers.empty, etc... Wed May 23 14:43:44 CDT 2001 Pass the rest of the ABORT test. This means we want to GENERATE aborts. This is the function tabort_8_4_8. Since we need to generate ABORTs in the CLOSED state, we want to have a way to send them without having to build a temporary association. We will generate a packet for this purpose and will call sctp_transmit_packet() on it at the appropriate time. DONE: - extract relevant data from chunk and endpoint. DONE: - change sctp_init_packet to not require the association. - build packet DONE: - build transport DONE: -- refactor sctp_add_transport() to create a sctp_make_transport(). DONE: --- Add fields for storing af_specific in proto. DONE: --- Initialize the af_specific parts of proto. DONE: --- Add a mechanism for fetching af_specific from proto. DONE: - add retval->packet DONE: - add retval->packet handling to SCTP_DISPOSITION_DISCARD. DONE: - add prototype for sctp_get_af_specific() DONE: - add prototype for sctp_make_transport() DONE: - fix call to t_new() DONE: - Update the state tables to call tabort. Tue May 29 11:53:18 CDT 2001 We are applying Jon Grimm's patch. DONE: - Edit patch DONE: - Apply patch DONE: - Add Jon's contact info DONE: - unit_test DONE: - frametest Add Xingang Guo's patch. DONE: - Edit patch DONE: - Apply patch DONE: - Check the lock coverage paths Main changes from patch: -- sctp_{lock|release}_sock() -- moved locking in sctp_sendmsg() to right before looking up association -- checking return values of copy_{to|from}_user -- goto out_unlock for EVERY setting of err in sctp_sendmsg() -- sctp_setsockopt() had returns with locked socket. DONE: - Update copyright and credits DONE: - is emsg->msg_flags properly initialized somewhere? -- Yes, but it might not conform to the API draft... DONE: - unit_test DONE: - frametest DONE: - kerneltest DONE: - Make new release DONE: - publish release to Source Forge. DONE: - Send note to list detailing changes to Xingang's patch... Thu Jun 14 17:41:04 CDT 2001 A plan for patch application. We have 5 patches: jgrimm_delayed_ia_01_Jun.patch (subsumed by next one) jgrimm_tsn_lt_04_Jun.patch (subsumed by next one) EDITED: jgrimm_ecn_06_Jun.patch DONE: We still want to edit Jon's patch to deal with the ecn_allowed vs. ecn_capable issue. Mon Jun 18 12:07:32 CDT 2001 DONE: xingang_patch.debug.v011 xingang_patch.INIT_ACK.v011 Wed Jun 20 18:06:20 CDT 2001 Fix Daisy's bug: Null pointer check needed for chunks sctp_make_chunk() may return a NULL pointer, therefore, every place that sctp_make_chunk() is called needs to verify the return value to prevent from using any NULL pointer down the road. Right now, in 2_4_1-0_1_1, all of these routines, such as sctp_make_init(), sctp_make_data_empty(), sctp_make_sack(), etc, uses the return value from sctp_make_chunk() assuming that it is non-NULL. Here are functions which are propigating the NULL bug: sctp_make_init Wed Aug 1 13:25:18 CDT 2001 DONE: Apply Jon's patch DONE: Remove definitions of *Unified* DONE: Add comments on deviation from CWR rules. DONE: Make myNextTSN an atomic_t. DONE: Create sctp_config_packet(vTag, ecn_handler), and (*packet->config)() Move last_cwr_tsn adjustment into sctp_handle_congestion(). Move CWR generation into the state function? Fri Aug 17 18:38:29 CDT 2001 We're going through sctp_ipv6.0_1_2.patch. We've read everything but the tests. Mon Aug 20 15:37:47 CDT 2001 We're about to plunge back into the ipv6 patch, mostly after the SCTP Business meeting at 4pm, hopefully after we commit the latest changes (the ones to the style guide and to sctp_v4_rcv().) Thu Aug 23 13:45:53 CDT 2001 We cleared all outstanding integration (bug fixes, cmd_seq_t, ChunkDesc overallocation...). We also refactored the retval timers to be sctp_cmd_seq_t's. Now the trick is to get a test to fail because of the sctp_gen_sack() timer issue. Fri Aug 24 18:51:20 CDT 2001 Well, we got the test (ft_frame_sack) to fail. Not quite where we wanted...but we have a pretty cool test to make up for it. Where we *do* fail is by sending one too many SACKs (for the test, Piggy). We send a SACK for every odd numbered packet without considering SACK timeouts. This is legal, but inelegant and screwy. On Monday, we're going to check and see how much torture this will be to refactor. Then we'll probably do it anyway, code-starved as we are. Mon Aug 27 18:04:01 CDT 2001 OK, we are now passing ft_frame_sack, but ft_frame_ecn_basic fails. The problem is that we need to do ECN processing BEFORE we generate the SACK, but we are now generating the SACK in the side effects interpreter, which runs BEFORE the rest of all that stuff. The fix is to convert ECN processing to use retval->commands. Tue Aug 28 17:50:27 CDT 2001 Notes on ft_frame_lostpackets (mysterious dup TSNs): ??? Shouldn't we be sacking 98d? AAA No, because c and d are in the same packet ??? How many times do we start the SACK timer per packet? Should this be conditional on end_of_packet? AAA I think once per packet, since we're running a small danger of ST expiration before all data is processed. Might as well wait. We do now. NNN In the non-sequential case, our sack doesn't gap ack (that's one), also, we sack on the reception of the middle data in that test, and then (presumably) stop the sack timer so the "forward time until sack" there does nothing. NNN When the rtx timer expires, we naturally deliver all 3 things in queue, and the middle one (a dup TSN) kills the test. So: a) we should gap ack, and b) dup TSNs shouldn't kill the test. SACK hunt: doTSNupdate looks ok. In sctp_gen_sack(), we would (I think) have sent f because it's an alternate data packet, but we also send it because it's a gap-- (AP(max_tsn_seen) is above the AP(CTSNAckP)). AHA! sctp_make_sack() evades the whole topic of gap acking! That'll do it... Wed Aug 29 10:41:31 CDT 2001 Upgraded ft_frame_lostpackets to see a gap-ack-unconditional sack. ??? How can we fail the test when we don't gap ack without failing on dup TSNs? Wed Aug 29 15:15:29 CDT 2001 We've now created a stub for duplicate reporting--a duplicate TSN is no longer an error. We're going to eliminate our duplicate detection test and see if we now could pass ft_frame_lostpackets... Yep! The new test is meaningful! Our new goal is to make the revised ft_frame_lostpackets pass by implementing gap acks. But first... Change to using Jon's new data structure! Integrate sctp_tsnmap_t. Implement gap acks. Wed Aug 29 16:34:55 CDT 2001 We are going through lksctp-2_4_1-0_1_13.tsnmap.patch2 preparing comments and massaging the patch. We need to finish this and apply the patch. Thu Aug 30 18:00:54 CDT 2001 We applied Jon's patches and refactored the TSN map code to use them. Tomorrow, Gap Acks! Fri Aug 31 14:44:37 CDT 2001 DONE: Add a descriptive comment for sctp_check_transmitted(). DONE: Remove the comment at sctp_outqueue.c:636. Fri Aug 31 15:59:34 CDT 2001 OK, frametest and unit_test both pass completely. Unfortunately, we seem to have fixed ft_frame_biggap. Since we did NOT implement fast retran, we were not expecting this. We want this test to fail again. There are two possibilities: 1) The test is wrong--it does not truely generate the big gap condition. 2) We introduced a bug which masks the big gap bug. 3) We really did fix the bug. It was possibility 3. Oops. We did not implement fast retran, but we DID make big gap a command rather than an error. Tue Sep 4 11:09:20 CDT 2001 We successfully transferred 10M of data from the user space implementation to a live lksctp. Throughput was pretty raw--about 25k/sec on a 100Mbit link with a PII-400, and 100 byte chunks. The fact that we do not advertise a growing rwnd hurts us a lot--we'd be about 1.8X faster if we did. That's still not extraordinarily fast--we really want to try this with the printk()s removed. Mon Sep 10 17:49:29 CDT 2001 A little integration makes the world go round. (patch.inaddr_any.04) lksctp-tools-1.0.16+dfsg.orig/bin/0000755000175000017500000000000012300634451016447 5ustar michaelmichaellksctp-tools-1.0.16+dfsg.orig/bin/aaaa0000755000175000017500000000071512300634451017263 0ustar michaelmichael#! /bin/sh # # Run all the stuff we need to generate the configure and Makefile.in # in the automake process. # # The order needs to be that. If autoheader does not run after # autoconf, it doesn't get all the symbols right. As automake requires # config.h.in, created by autoheader, it needs to run after it. # # $Id: aaaa,v 1.1.1.1 2002/08/06 22:31:05 inaky Exp $ set -ex aclocal autoconf autoheader # Set GNU strictness #automake --foreign automake --gnu lksctp-tools-1.0.16+dfsg.orig/bin/Makefile.am0000644000175000017500000000020312300634451020476 0ustar michaelmichael include $(top_srcdir)/Makefile.vars include $(top_srcdir)/Makefile.rules noinst_SCRIPTS = aaaa EXTRA_DIST += $(noinst_SCRIPTS) lksctp-tools-1.0.16+dfsg.orig/COPYING0000644000175000017500000004307712300634451016745 0ustar michaelmichael GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program 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 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.