diff options
Diffstat (limited to 'net/sctp/ulpevent.c')
| -rw-r--r-- | net/sctp/ulpevent.c | 199 | 
1 files changed, 70 insertions, 129 deletions
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index aa72e89c3ee..b6842fdb53d 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -22,25 +22,18 @@   * 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. + * along with GNU CC; see the file COPYING.  If not, see + * <http://www.gnu.org/licenses/>.   *   * Please send any bug reports or fixes you make to the   * email address(es): - *    lksctp developers <lksctp-developers@lists.sourceforge.net> - * - * Or submit a bug report through the following website: - *    http://www.sf.net/projects/lksctp + *    lksctp developers <linux-sctp@vger.kernel.org>   *   * Written or modified by:   *    Jon Grimm             <jgrimm@us.ibm.com>   *    La Monte H.P. Yarroll <piggy@acm.org>   *    Ardelle Fan	    <ardelle.fan@intel.com>   *    Sridhar Samudrala     <sri@us.ibm.com> - * - * Any bugs reported given to us we will try to fix... any fixes shared will - * be incorporated into the next SCTP release.   */  #include <linux/slab.h> @@ -57,9 +50,9 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);  /* Initialize an ULP event from an given skb.  */ -SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, -				    int msg_flags, -				    unsigned int len) +static void sctp_ulpevent_init(struct sctp_ulpevent *event, +			       int msg_flags, +			       unsigned int len)  {  	memset(event, 0, sizeof(struct sctp_ulpevent));  	event->msg_flags = msg_flags; @@ -67,8 +60,8 @@ SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event,  }  /* Create a new sctp_ulpevent.  */ -SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, -						    gfp_t gfp) +static struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, +					       gfp_t gfp)  {  	struct sctp_ulpevent *event;  	struct sk_buff *skb; @@ -373,9 +366,10 @@ fail:   * specification [SCTP] and any extensions for a list of possible   * error formats.   */ -struct sctp_ulpevent *sctp_ulpevent_make_remote_error( -	const struct sctp_association *asoc, struct sctp_chunk *chunk, -	__u16 flags, gfp_t gfp) +struct sctp_ulpevent * +sctp_ulpevent_make_remote_error(const struct sctp_association *asoc, +				struct sctp_chunk *chunk, __u16 flags, +				gfp_t gfp)  {  	struct sctp_ulpevent *event;  	struct sctp_remote_error *sre; @@ -394,8 +388,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(  	/* Copy the skb to a new skb with room for us to prepend  	 * notification with.  	 */ -	skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), -			      0, gfp); +	skb = skb_copy_expand(chunk->skb, sizeof(*sre), 0, gfp);  	/* Pull off the rest of the cause TLV from the chunk.  */  	skb_pull(chunk->skb, elen); @@ -406,62 +399,21 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(  	event = sctp_skb2event(skb);  	sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); -	sre = (struct sctp_remote_error *) -		skb_push(skb, sizeof(struct sctp_remote_error)); +	sre = (struct sctp_remote_error *) skb_push(skb, sizeof(*sre));  	/* Trim the buffer to the right length.  */ -	skb_trim(skb, sizeof(struct sctp_remote_error) + elen); +	skb_trim(skb, sizeof(*sre) + elen); -	/* Socket Extensions for SCTP -	 * 5.3.1.3 SCTP_REMOTE_ERROR -	 * -	 * sre_type: -	 *   It should be SCTP_REMOTE_ERROR. -	 */ +	/* RFC6458, Section 6.1.3. SCTP_REMOTE_ERROR */ +	memset(sre, 0, sizeof(*sre));  	sre->sre_type = SCTP_REMOTE_ERROR; - -	/* -	 * Socket Extensions for SCTP -	 * 5.3.1.3 SCTP_REMOTE_ERROR -	 * -	 * sre_flags: 16 bits (unsigned integer) -	 *   Currently unused. -	 */  	sre->sre_flags = 0; - -	/* Socket Extensions for SCTP -	 * 5.3.1.3 SCTP_REMOTE_ERROR -	 * -	 * sre_length: sizeof (__u32) -	 * -	 * This field is the total length of the notification data, -	 * including the notification header. -	 */  	sre->sre_length = skb->len; - -	/* Socket Extensions for SCTP -	 * 5.3.1.3 SCTP_REMOTE_ERROR -	 * -	 * sre_error: 16 bits (unsigned integer) -	 * This value represents one of the Operational Error causes defined in -	 * the SCTP specification, in network byte order. -	 */  	sre->sre_error = cause; - -	/* Socket Extensions for SCTP -	 * 5.3.1.3 SCTP_REMOTE_ERROR -	 * -	 * sre_assoc_id: sizeof (sctp_assoc_t) -	 * -	 * The association id field, holds the identifier for the association. -	 * All notifications for a given association have the same association -	 * identifier.  For TCP style socket, this field is ignored. -	 */  	sctp_ulpevent_set_owner(event, asoc);  	sre->sre_assoc_id = sctp_assoc2id(asoc);  	return event; -  fail:  	return NULL;  } @@ -554,7 +506,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(  	memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));  	/* Per TSVWG discussion with Randy. Allow the application to -	 * ressemble a fragmented message. +	 * reassemble a fragmented message.  	 */  	ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags; @@ -702,7 +654,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,  	if (rx_count >= asoc->base.sk->sk_rcvbuf) {  		if ((asoc->base.sk->sk_userlocks & SOCK_RCVBUF_LOCK) || -		    (!sk_rmem_schedule(asoc->base.sk, chunk->skb->truesize))) +		    (!sk_rmem_schedule(asoc->base.sk, chunk->skb, +				       chunk->skb->truesize)))  			goto fail;  	} @@ -715,7 +668,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,  	 * can mark it as received so the tsn_map is updated correctly.  	 */  	if (sctp_tsnmap_mark(&asoc->peer.tsn_map, -			     ntohl(chunk->subh.data_hdr->tsn))) +			     ntohl(chunk->subh.data_hdr->tsn), +			     chunk->transport))  		goto fail_mark;  	/* First calculate the padding, so we don't inadvertently @@ -843,7 +797,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_authkey(  	ak = (struct sctp_authkey_event *)  		skb_put(skb, sizeof(struct sctp_authkey_event)); -	ak->auth_type = SCTP_AUTHENTICATION_INDICATION; +	ak->auth_type = SCTP_AUTHENTICATION_EVENT;  	ak->auth_flags = 0;  	ak->auth_length = sizeof(struct sctp_authkey_event); @@ -862,6 +816,34 @@ fail:  	return NULL;  } +/* + * Socket Extensions for SCTP + * 6.3.10. SCTP_SENDER_DRY_EVENT + */ +struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( +	const struct sctp_association *asoc, gfp_t gfp) +{ +	struct sctp_ulpevent *event; +	struct sctp_sender_dry_event *sdry; +	struct sk_buff *skb; + +	event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event), +				  MSG_NOTIFICATION, gfp); +	if (!event) +		return NULL; + +	skb = sctp_event2skb(event); +	sdry = (struct sctp_sender_dry_event *) +		skb_put(skb, sizeof(struct sctp_sender_dry_event)); + +	sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT; +	sdry->sender_dry_flags = 0; +	sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event); +	sctp_ulpevent_set_owner(event, asoc); +	sdry->sender_dry_assoc_id = sctp_assoc2id(asoc); + +	return event; +}  /* Return the notification type, assuming this is a notification   * event. @@ -876,7 +858,9 @@ __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)  	return notification->sn_header.sn_type;  } -/* Copy out the sndrcvinfo into a msghdr.  */ +/* RFC6458, Section 5.3.2. SCTP Header Information Structure + * (SCTP_SNDRCV, DEPRECATED) + */  void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,  				   struct msghdr *msghdr)  { @@ -885,74 +869,21 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,  	if (sctp_ulpevent_is_notification(event))  		return; -	/* Sockets API Extensions for SCTP -	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) -	 * -	 * sinfo_stream: 16 bits (unsigned integer) -	 * -	 * For recvmsg() the SCTP stack places the message's stream number in -	 * this value. -	*/ +	memset(&sinfo, 0, sizeof(sinfo));  	sinfo.sinfo_stream = event->stream; -	/* sinfo_ssn: 16 bits (unsigned integer) -	 * -	 * For recvmsg() this value contains the stream sequence number that -	 * the remote endpoint placed in the DATA chunk.  For fragmented -	 * messages this is the same number for all deliveries of the message -	 * (if more than one recvmsg() is needed to read the message). -	 */  	sinfo.sinfo_ssn = event->ssn; -	/* sinfo_ppid: 32 bits (unsigned integer) -	 * -	 * In recvmsg() this value is -	 * the same information that was passed by the upper layer in the peer -	 * application.  Please note that byte order issues are NOT accounted -	 * for and this information is passed opaquely by the SCTP stack from -	 * one end to the other. -	 */  	sinfo.sinfo_ppid = event->ppid; -	/* 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. -	 * -	 * recvmsg() flags: -	 * -	 * SCTP_UNORDERED - This flag is present when the message was sent -	 *                 non-ordered. -	 */  	sinfo.sinfo_flags = event->flags; -	/* sinfo_tsn: 32 bit (unsigned integer) -	 * -	 * For the receiving side, this field holds a TSN that was -	 * assigned to one of the SCTP Data Chunks. -	 */  	sinfo.sinfo_tsn = event->tsn; -	/* sinfo_cumtsn: 32 bit (unsigned integer) -	 * -	 * This field will hold the current cumulative TSN as -	 * known by the underlying SCTP layer.  Note this field is -	 * ignored when sending and only valid for a receive -	 * operation when sinfo_flags are set to SCTP_UNORDERED. -	 */  	sinfo.sinfo_cumtsn = event->cumtsn; -	/* sinfo_assoc_id: sizeof (sctp_assoc_t) -	 * -	 * The association handle field, sinfo_assoc_id, holds the identifier -	 * for the association announced in the COMMUNICATION_UP notification. -	 * All notifications for a given association have the same identifier. -	 * Ignored for one-to-one style sockets. -	 */  	sinfo.sinfo_assoc_id = sctp_assoc2id(event->asoc); - -	/* context value that is set via SCTP_CONTEXT socket option. */ +	/* Context value that is set via SCTP_CONTEXT socket option. */  	sinfo.sinfo_context = event->asoc->default_rcv_context; -  	/* These fields are not used while receiving. */  	sinfo.sinfo_timetolive = 0;  	put_cmsg(msghdr, IPPROTO_SCTP, SCTP_SNDRCV, -		 sizeof(struct sctp_sndrcvinfo), (void *)&sinfo); +		 sizeof(sinfo), &sinfo);  }  /* Do accounting for bytes received and hold a reference to the association @@ -1053,9 +984,19 @@ void sctp_ulpevent_free(struct sctp_ulpevent *event)  }  /* Purge the skb lists holding ulpevents. */ -void sctp_queue_purge_ulpevents(struct sk_buff_head *list) +unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list)  {  	struct sk_buff *skb; -	while ((skb = skb_dequeue(list)) != NULL) -		sctp_ulpevent_free(sctp_skb2event(skb)); +	unsigned int data_unread = 0; + +	while ((skb = skb_dequeue(list)) != NULL) { +		struct sctp_ulpevent *event = sctp_skb2event(skb); + +		if (!sctp_ulpevent_is_notification(event)) +			data_unread += skb->len; + +		sctp_ulpevent_free(event); +	} + +	return data_unread;  }  | 
