| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 1 | 2 | /* SCTP kernel implementation | 
|---|
| 2 | 3 | * (C) Copyright IBM Corp. 2003, 2004 | 
|---|
| 3 | 4 | * | 
|---|
| 4 | 5 | * This file is part of the SCTP kernel implementation | 
|---|
| 5 | 6 | * | 
|---|
| 6 | 7 | * This file contains the code relating the chunk abstraction. | 
|---|
| 7 |  | - * | 
|---|
| 8 |  | - * This SCTP implementation is free software; | 
|---|
| 9 |  | - * you can redistribute it and/or modify it under the terms of | 
|---|
| 10 |  | - * the GNU General Public License as published by | 
|---|
| 11 |  | - * the Free Software Foundation; either version 2, or (at your option) | 
|---|
| 12 |  | - * any later version. | 
|---|
| 13 |  | - * | 
|---|
| 14 |  | - * This SCTP implementation is distributed in the hope that it | 
|---|
| 15 |  | - * will be useful, but WITHOUT ANY WARRANTY; without even the implied | 
|---|
| 16 |  | - *                 ************************ | 
|---|
| 17 |  | - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|---|
| 18 |  | - * See the GNU General Public License for more details. | 
|---|
| 19 |  | - * | 
|---|
| 20 |  | - * You should have received a copy of the GNU General Public License | 
|---|
| 21 |  | - * along with GNU CC; see the file COPYING.  If not, see | 
|---|
| 22 |  | - * <http://www.gnu.org/licenses/>. | 
|---|
| 23 | 8 | * | 
|---|
| 24 | 9 | * Please send any bug reports or fixes you make to the | 
|---|
| 25 | 10 | * email address(es): | 
|---|
| .. | .. | 
|---|
| 86 | 71 | /* Final destructruction of datamsg memory. */ | 
|---|
| 87 | 72 | static void sctp_datamsg_destroy(struct sctp_datamsg *msg) | 
|---|
| 88 | 73 | { | 
|---|
|  | 74 | +	struct sctp_association *asoc = NULL; | 
|---|
| 89 | 75 | struct list_head *pos, *temp; | 
|---|
| 90 | 76 | struct sctp_chunk *chunk; | 
|---|
| 91 |  | -	struct sctp_sock *sp; | 
|---|
| 92 | 77 | struct sctp_ulpevent *ev; | 
|---|
| 93 |  | -	struct sctp_association *asoc = NULL; | 
|---|
| 94 |  | -	int error = 0, notify; | 
|---|
| 95 |  | - | 
|---|
| 96 |  | -	/* If we failed, we may need to notify. */ | 
|---|
| 97 |  | -	notify = msg->send_failed ? -1 : 0; | 
|---|
|  | 78 | +	int error, sent; | 
|---|
| 98 | 79 |  | 
|---|
| 99 | 80 | /* Release all references. */ | 
|---|
| 100 | 81 | list_for_each_safe(pos, temp, &msg->chunks) { | 
|---|
| 101 | 82 | list_del_init(pos); | 
|---|
| 102 | 83 | chunk = list_entry(pos, struct sctp_chunk, frag_list); | 
|---|
| 103 |  | -		/* Check whether we _really_ need to notify. */ | 
|---|
| 104 |  | -		if (notify < 0) { | 
|---|
| 105 |  | -			asoc = chunk->asoc; | 
|---|
| 106 |  | -			if (msg->send_error) | 
|---|
| 107 |  | -				error = msg->send_error; | 
|---|
| 108 |  | -			else | 
|---|
| 109 |  | -				error = asoc->outqueue.error; | 
|---|
| 110 | 84 |  | 
|---|
| 111 |  | -			sp = sctp_sk(asoc->base.sk); | 
|---|
| 112 |  | -			notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED, | 
|---|
| 113 |  | -							    &sp->subscribe); | 
|---|
|  | 85 | +		if (!msg->send_failed) { | 
|---|
|  | 86 | +			sctp_chunk_put(chunk); | 
|---|
|  | 87 | +			continue; | 
|---|
| 114 | 88 | } | 
|---|
| 115 | 89 |  | 
|---|
| 116 |  | -		/* Generate a SEND FAILED event only if enabled. */ | 
|---|
| 117 |  | -		if (notify > 0) { | 
|---|
| 118 |  | -			int sent; | 
|---|
| 119 |  | -			if (chunk->has_tsn) | 
|---|
| 120 |  | -				sent = SCTP_DATA_SENT; | 
|---|
| 121 |  | -			else | 
|---|
| 122 |  | -				sent = SCTP_DATA_UNSENT; | 
|---|
|  | 90 | +		asoc = chunk->asoc; | 
|---|
|  | 91 | +		error = msg->send_error ?: asoc->outqueue.error; | 
|---|
|  | 92 | +		sent = chunk->has_tsn ? SCTP_DATA_SENT : SCTP_DATA_UNSENT; | 
|---|
| 123 | 93 |  | 
|---|
|  | 94 | +		if (sctp_ulpevent_type_enabled(asoc->subscribe, | 
|---|
|  | 95 | +					       SCTP_SEND_FAILED)) { | 
|---|
| 124 | 96 | ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent, | 
|---|
| 125 | 97 | error, GFP_ATOMIC); | 
|---|
|  | 98 | +			if (ev) | 
|---|
|  | 99 | +				asoc->stream.si->enqueue_event(&asoc->ulpq, ev); | 
|---|
|  | 100 | +		} | 
|---|
|  | 101 | + | 
|---|
|  | 102 | +		if (sctp_ulpevent_type_enabled(asoc->subscribe, | 
|---|
|  | 103 | +					       SCTP_SEND_FAILED_EVENT)) { | 
|---|
|  | 104 | +			ev = sctp_ulpevent_make_send_failed_event(asoc, chunk, | 
|---|
|  | 105 | +								  sent, error, | 
|---|
|  | 106 | +								  GFP_ATOMIC); | 
|---|
| 126 | 107 | if (ev) | 
|---|
| 127 | 108 | asoc->stream.si->enqueue_event(&asoc->ulpq, ev); | 
|---|
| 128 | 109 | } | 
|---|
| .. | .. | 
|---|
| 194 | 175 | if (unlikely(!max_data)) { | 
|---|
| 195 | 176 | max_data = sctp_min_frag_point(sctp_sk(asoc->base.sk), | 
|---|
| 196 | 177 | sctp_datachk_len(&asoc->stream)); | 
|---|
| 197 |  | -		pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing max_data to default minimum (%Zu)", | 
|---|
|  | 178 | +		pr_warn_ratelimited("%s: asoc:%p frag_point is zero, forcing max_data to default minimum (%zu)", | 
|---|
| 198 | 179 | __func__, asoc, max_data); | 
|---|
| 199 | 180 | } | 
|---|
| 200 | 181 |  | 
|---|
| 201 |  | -	/* If the the peer requested that we authenticate DATA chunks | 
|---|
|  | 182 | +	/* If the peer requested that we authenticate DATA chunks | 
|---|
| 202 | 183 | * we need to account for bundling of the AUTH chunks along with | 
|---|
| 203 | 184 | * DATA. | 
|---|
| 204 | 185 | */ | 
|---|
| .. | .. | 
|---|
| 244 | 225 | if (msg_len >= first_len) { | 
|---|
| 245 | 226 | msg->can_delay = 0; | 
|---|
| 246 | 227 | if (msg_len > first_len) | 
|---|
| 247 |  | -			SCTP_INC_STATS(sock_net(asoc->base.sk), | 
|---|
|  | 228 | +			SCTP_INC_STATS(asoc->base.net, | 
|---|
| 248 | 229 | SCTP_MIB_FRAGUSRMSGS); | 
|---|
| 249 | 230 | } else { | 
|---|
| 250 | 231 | /* Which may be the only one... */ | 
|---|