chunk.c 10.2 KB
Newer Older
1
/* SCTP kernel implementation
L
Linus Torvalds 已提交
2 3
 * (C) Copyright IBM Corp. 2003, 2004
 *
4
 * This file is part of the SCTP kernel implementation
L
Linus Torvalds 已提交
5
 *
6
 * This file contains the code relating the chunk abstraction.
L
Linus Torvalds 已提交
7
 *
8
 * This SCTP implementation is free software;
L
Linus Torvalds 已提交
9 10 11 12 13
 * 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.
 *
14
 * This SCTP implementation is distributed in the hope that it
L
Linus Torvalds 已提交
15 16 17 18 19 20
 * 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
21 22
 * along with GNU CC; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>.
L
Linus Torvalds 已提交
23 24 25
 *
 * Please send any bug reports or fixes you make to the
 * email address(es):
26
 *    lksctp developers <linux-sctp@vger.kernel.org>
L
Linus Torvalds 已提交
27 28 29 30 31 32
 *
 * Written or modified by:
 *    Jon Grimm             <jgrimm@us.ibm.com>
 *    Sridhar Samudrala     <sri@us.ibm.com>
 */

33 34
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

L
Linus Torvalds 已提交
35 36 37 38 39
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/inet.h>
#include <linux/skbuff.h>
40
#include <linux/slab.h>
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51
#include <net/sock.h>
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>

/* This file is mostly in anticipation of future work, but initially
 * populate with fragment tracking for an outbound message.
 */

/* Initialize datamsg from memory. */
static void sctp_datamsg_init(struct sctp_datamsg *msg)
{
52
	refcount_set(&msg->refcnt, 1);
L
Linus Torvalds 已提交
53 54
	msg->send_failed = 0;
	msg->send_error = 0;
55
	msg->can_delay = 1;
56
	msg->abandoned = 0;
L
Linus Torvalds 已提交
57 58 59 60 61
	msg->expires_at = 0;
	INIT_LIST_HEAD(&msg->chunks);
}

/* Allocate and initialize datamsg. */
62
static struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp)
L
Linus Torvalds 已提交
63 64 65
{
	struct sctp_datamsg *msg;
	msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
66
	if (msg) {
L
Linus Torvalds 已提交
67
		sctp_datamsg_init(msg);
68 69
		SCTP_DBG_OBJCNT_INC(datamsg);
	}
L
Linus Torvalds 已提交
70 71 72
	return msg;
}

73 74 75 76 77 78 79 80 81 82 83 84 85
void sctp_datamsg_free(struct sctp_datamsg *msg)
{
	struct sctp_chunk *chunk;

	/* This doesn't have to be a _safe vairant because
	 * sctp_chunk_free() only drops the refs.
	 */
	list_for_each_entry(chunk, &msg->chunks, frag_list)
		sctp_chunk_free(chunk);

	sctp_datamsg_put(msg);
}

L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
/* Final destructruction of datamsg memory. */
static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
{
	struct list_head *pos, *temp;
	struct sctp_chunk *chunk;
	struct sctp_sock *sp;
	struct sctp_ulpevent *ev;
	struct sctp_association *asoc = NULL;
	int error = 0, notify;

	/* If we failed, we may need to notify. */
	notify = msg->send_failed ? -1 : 0;

	/* Release all references. */
	list_for_each_safe(pos, temp, &msg->chunks) {
		list_del_init(pos);
		chunk = list_entry(pos, struct sctp_chunk, frag_list);
		/* Check whether we _really_ need to notify. */
		if (notify < 0) {
			asoc = chunk->asoc;
			if (msg->send_error)
				error = msg->send_error;
			else
				error = asoc->outqueue.error;

			sp = sctp_sk(asoc->base.sk);
			notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED,
							    &sp->subscribe);
		}

		/* Generate a SEND FAILED event only if enabled. */
		if (notify > 0) {
			int sent;
			if (chunk->has_tsn)
				sent = SCTP_DATA_SENT;
			else
				sent = SCTP_DATA_UNSENT;

			ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
							    error, GFP_ATOMIC);
			if (ev)
127
				asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
L
Linus Torvalds 已提交
128 129 130 131 132 133 134 135 136 137 138 139
		}

		sctp_chunk_put(chunk);
	}

	SCTP_DBG_OBJCNT_DEC(datamsg);
	kfree(msg);
}

/* Hold a reference. */
static void sctp_datamsg_hold(struct sctp_datamsg *msg)
{
140
	refcount_inc(&msg->refcnt);
L
Linus Torvalds 已提交
141 142 143 144 145
}

/* Release a reference. */
void sctp_datamsg_put(struct sctp_datamsg *msg)
{
146
	if (refcount_dec_and_test(&msg->refcnt))
L
Linus Torvalds 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
		sctp_datamsg_destroy(msg);
}

/* Assign a chunk to this datamsg. */
static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
{
	sctp_datamsg_hold(msg);
	chunk->msg = msg;
}


/* A data chunk can have a maximum payload of (2^16 - 20).  Break
 * down any such message into smaller chunks.  Opportunistically, fragment
 * the chunks down to the current MTU constraints.  We may get refragmented
 * later if the PMTU changes, but it is _much better_ to fragment immediately
 * with a reasonable guess than always doing our fragmentation on the
 * soft-interrupt.
 */
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
					    struct sctp_sndrcvinfo *sinfo,
167
					    struct iov_iter *from)
L
Linus Torvalds 已提交
168
{
169 170
	size_t len, first_len, max_data, remaining;
	size_t msg_len = iov_iter_count(from);
X
Xin Long 已提交
171
	struct sctp_shared_key *shkey = NULL;
172
	struct list_head *pos, *temp;
L
Linus Torvalds 已提交
173 174
	struct sctp_chunk *chunk;
	struct sctp_datamsg *msg;
R
Richard Haines 已提交
175 176
	struct sctp_sock *sp;
	struct sctp_af *af;
177
	int err;
L
Linus Torvalds 已提交
178 179 180

	msg = sctp_datamsg_new(GFP_KERNEL);
	if (!msg)
181
		return ERR_PTR(-ENOMEM);
L
Linus Torvalds 已提交
182 183 184 185

	/* Note: Calculate this outside of the loop, so that all fragments
	 * have the same expiration.
	 */
X
Xin Long 已提交
186 187 188
	if (asoc->peer.prsctp_capable && sinfo->sinfo_timetolive &&
	    (SCTP_PR_TTL_ENABLED(sinfo->sinfo_flags) ||
	     !SCTP_PR_POLICY(sinfo->sinfo_flags)))
L
Linus Torvalds 已提交
189
		msg->expires_at = jiffies +
190
				  msecs_to_jiffies(sinfo->sinfo_timetolive);
191

192 193 194
	/* This is the biggest possible DATA chunk that can fit into
	 * the packet
	 */
R
Richard Haines 已提交
195 196 197 198 199
	sp = sctp_sk(asoc->base.sk);
	af = sp->pf->af;
	max_data = asoc->pathmtu - af->net_header_len -
		   sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream) -
		   af->ip_options_len(asoc->base.sk);
200
	max_data = SCTP_TRUNC4(max_data);
L
Linus Torvalds 已提交
201

202
	/* If the the peer requested that we authenticate DATA chunks
203
	 * we need to account for bundling of the AUTH chunks along with
204 205 206 207 208 209
	 * DATA.
	 */
	if (sctp_auth_send_cid(SCTP_CID_DATA, asoc)) {
		struct sctp_hmac *hmac_desc = sctp_auth_asoc_get_hmac(asoc);

		if (hmac_desc)
210
			max_data -= SCTP_PAD4(sizeof(struct sctp_auth_chunk) +
211
					      hmac_desc->hmac_len);
X
Xin Long 已提交
212

213 214 215 216 217 218 219 220 221 222
		if (sinfo->sinfo_tsn &&
		    sinfo->sinfo_ssn != asoc->active_key_id) {
			shkey = sctp_auth_get_shkey(asoc, sinfo->sinfo_ssn);
			if (!shkey) {
				err = -EINVAL;
				goto errout;
			}
		} else {
			shkey = asoc->shkey;
		}
223 224
	}

225 226
	/* Check what's our max considering the above */
	max_data = min_t(size_t, max_data, asoc->frag_point);
227

228 229
	/* Set first_len and then account for possible bundles on first frag */
	first_len = max_data;
L
Linus Torvalds 已提交
230

231 232 233 234 235 236 237 238 239
	/* Check to see if we have a pending SACK and try to let it be bundled
	 * with this message.  Do this if we don't have any data queued already.
	 * To check that, look at out_qlen and retransmit list.
	 * NOTE: we will not reduce to account for SACK, if the message would
	 * not have been fragmented.
	 */
	if (timer_pending(&asoc->timers[SCTP_EVENT_TIMEOUT_SACK]) &&
	    asoc->outqueue.out_qlen == 0 &&
	    list_empty(&asoc->outqueue.retransmit) &&
240
	    msg_len > max_data)
241
		first_len -= SCTP_PAD4(sizeof(struct sctp_sack_chunk));
242

L
Linus Torvalds 已提交
243
	/* Encourage Cookie-ECHO bundling. */
244
	if (asoc->state < SCTP_STATE_COOKIE_ECHOED)
245
		first_len -= SCTP_ARBITRARY_COOKIE_ECHO_LEN;
246 247 248

	/* Account for a different sized first fragment */
	if (msg_len >= first_len) {
249
		msg->can_delay = 0;
250
		SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_FRAGUSRMSGS);
251 252 253 254
	} else {
		/* Which may be the only one... */
		first_len = msg_len;
	}
L
Linus Torvalds 已提交
255

256 257 258
	/* Create chunks for all DATA chunks. */
	for (remaining = msg_len; remaining; remaining -= len) {
		u8 frag = SCTP_DATA_MIDDLE_FRAG;
L
Linus Torvalds 已提交
259

260 261
		if (remaining == msg_len) {
			/* First frag, which may also be the last */
L
Linus Torvalds 已提交
262
			frag |= SCTP_DATA_FIRST_FRAG;
263 264 265 266 267
			len = first_len;
		} else {
			/* Middle frags */
			len = max_data;
		}
L
Linus Torvalds 已提交
268

269 270 271
		if (len >= remaining) {
			/* Last frag, which may also be the first */
			len = remaining;
L
Linus Torvalds 已提交
272 273
			frag |= SCTP_DATA_LAST_FRAG;

274 275 276 277 278 279 280 281 282
			/* The application requests to set the I-bit of the
			 * last DATA chunk of a user message when providing
			 * the user message to the SCTP implementation.
			 */
			if ((sinfo->sinfo_flags & SCTP_EOF) ||
			    (sinfo->sinfo_flags & SCTP_SACK_IMMEDIATELY))
				frag |= SCTP_DATA_SACK_IMM;
		}

283 284
		chunk = asoc->stream.si->make_datafrag(asoc, sinfo, len, frag,
						       GFP_KERNEL);
285 286
		if (!chunk) {
			err = -ENOMEM;
L
Linus Torvalds 已提交
287
			goto errout;
288 289
		}

290
		err = sctp_user_addto_chunk(chunk, len, from);
L
Linus Torvalds 已提交
291
		if (err < 0)
292
			goto errout_chunk_free;
L
Linus Torvalds 已提交
293

X
Xin Long 已提交
294 295
		chunk->shkey = shkey;

L
Linus Torvalds 已提交
296
		/* Put the chunk->skb back into the form expected by send.  */
297 298
		__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr -
				       chunk->skb->data);
L
Linus Torvalds 已提交
299 300 301 302 303 304 305

		sctp_datamsg_assign(msg, chunk);
		list_add_tail(&chunk->frag_list, &msg->chunks);
	}

	return msg;

306 307 308
errout_chunk_free:
	sctp_chunk_free(chunk);

L
Linus Torvalds 已提交
309 310 311 312 313 314
errout:
	list_for_each_safe(pos, temp, &msg->chunks) {
		list_del_init(pos);
		chunk = list_entry(pos, struct sctp_chunk, frag_list);
		sctp_chunk_free(chunk);
	}
315
	sctp_datamsg_put(msg);
316

317
	return ERR_PTR(err);
L
Linus Torvalds 已提交
318 319 320 321 322
}

/* Check whether this message has expired. */
int sctp_chunk_abandoned(struct sctp_chunk *chunk)
{
X
Xin Long 已提交
323
	if (!chunk->asoc->peer.prsctp_capable)
L
Linus Torvalds 已提交
324 325
		return 0;

326 327 328
	if (chunk->msg->abandoned)
		return 1;

329 330 331 332
	if (!chunk->has_tsn &&
	    !(chunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG))
		return 0;

X
Xin Long 已提交
333
	if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
334
	    time_after(jiffies, chunk->msg->expires_at)) {
335
		struct sctp_stream_out *streamout =
336
			&chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
337 338

		if (chunk->sent_count) {
X
Xin Long 已提交
339
			chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
340
			streamout->ext->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
341
		} else {
X
Xin Long 已提交
342
			chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
343
			streamout->ext->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
344
		}
345
		chunk->msg->abandoned = 1;
L
Linus Torvalds 已提交
346
		return 1;
X
Xin Long 已提交
347
	} else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
348
		   chunk->sent_count > chunk->sinfo.sinfo_timetolive) {
349
		struct sctp_stream_out *streamout =
350
			&chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
351

X
Xin Long 已提交
352
		chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
353
		streamout->ext->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
354
		chunk->msg->abandoned = 1;
X
Xin Long 已提交
355
		return 1;
X
Xin Long 已提交
356 357 358
	} else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) &&
		   chunk->msg->expires_at &&
		   time_after(jiffies, chunk->msg->expires_at)) {
359
		chunk->msg->abandoned = 1;
X
Xin Long 已提交
360
		return 1;
X
Xin Long 已提交
361
	}
X
Xin Long 已提交
362
	/* PRIO policy is processed by sendmsg, not here */
L
Linus Torvalds 已提交
363 364 365 366 367 368 369 370 371 372

	return 0;
}

/* This chunk (and consequently entire message) has failed in its sending. */
void sctp_chunk_fail(struct sctp_chunk *chunk, int error)
{
	chunk->msg->send_failed = 1;
	chunk->msg->send_error = error;
}