OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sctp/] [chunk.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* SCTP kernel reference Implementation
2
 * Copyright (c) 2003 International Business Machines Corp.
3
 *
4
 * This file is part of the SCTP kernel reference Implementation
5
 *
6
 * This file contains the code relating the the chunk abstraction.
7
 *
8
 * The SCTP reference 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
 * The SCTP reference 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, write to
22
 * the Free Software Foundation, 59 Temple Place - Suite 330,
23
 * Boston, MA 02111-1307, USA.
24
 *
25
 * Please send any bug reports or fixes you make to the
26
 * email address(es):
27
 *    lksctp developers <lksctp-developers@lists.sourceforge.net>
28
 *
29
 * Or submit a bug report through the following website:
30
 *    http://www.sf.net/projects/lksctp
31
 *
32
 * Written or modified by:
33
 *    Jon Grimm             <jgrimm@us.ibm.com>
34
 *
35
 * Any bugs reported given to us we will try to fix... any fixes shared will
36
 * be incorporated into the next SCTP release.
37
 */
38
 
39
#include <linux/types.h>
40
#include <linux/kernel.h>
41
#include <linux/net.h>
42
#include <linux/inet.h>
43
#include <linux/skbuff.h>
44
#include <net/sock.h>
45
#include <net/sctp/sctp.h>
46
#include <net/sctp/sm.h>
47
 
48
/* This file is mostly in anticipation of future work, but initially
49
 * populate with fragment tracking for an outbound message.
50
 */
51
 
52
/* Initialize datamsg from memory. */
53
void sctp_datamsg_init(struct sctp_datamsg *msg)
54
{
55
        atomic_set(&msg->refcnt, 1);
56
        msg->send_failed = 0;
57
        msg->send_error = 0;
58
        msg->can_expire = 0;
59
        INIT_LIST_HEAD(&msg->chunks);
60
}
61
 
62
/* Allocate and initialize datamsg. */
63
struct sctp_datamsg *sctp_datamsg_new(int gfp)
64
{
65
        struct sctp_datamsg *msg;
66
        msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
67
        if (msg)
68
                sctp_datamsg_init(msg);
69
        SCTP_DBG_OBJCNT_INC(datamsg);
70
        return msg;
71
}
72
 
73
/* Final destructruction of datamsg memory. */
74
static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
75
{
76
        struct list_head *pos, *temp;
77
        struct sctp_chunk *chunk;
78
        struct sctp_opt *sp;
79
        struct sctp_ulpevent *ev;
80
        struct sctp_association *asoc = NULL;
81
        int error = 0, notify;
82
 
83
        /* If we failed, we may need to notify. */
84
        notify = msg->send_failed ? -1 : 0;
85
 
86
        /* Release all references. */
87
        list_for_each_safe(pos, temp, &msg->chunks) {
88
                list_del_init(pos);
89
                chunk = list_entry(pos, struct sctp_chunk, frag_list);
90
                /* Check whether we _really_ need to notify. */
91
                if (notify < 0) {
92
                        asoc = chunk->asoc;
93
                        if (msg->send_error)
94
                                error = msg->send_error;
95
                        else
96
                                error = asoc->outqueue.error;
97
 
98
                        sp = sctp_sk(asoc->base.sk);
99
                        notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED,
100
                                                            &sp->subscribe);
101
                }
102
 
103
                /* Generate a SEND FAILED event only if enabled. */
104
                if (notify > 0) {
105
                        int sent;
106
                        if (chunk->has_tsn)
107
                                sent = SCTP_DATA_SENT;
108
                        else
109
                                sent = SCTP_DATA_UNSENT;
110
 
111
                        ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
112
                                                            error, GFP_ATOMIC);
113
                        if (ev)
114
                                sctp_ulpq_tail_event(&asoc->ulpq, ev);
115
                }
116
 
117
                sctp_chunk_put(chunk);
118
        }
119
 
120
        SCTP_DBG_OBJCNT_DEC(datamsg);
121
        kfree(msg);
122
}
123
 
124
/* Hold a reference. */
125
void sctp_datamsg_hold(struct sctp_datamsg *msg)
126
{
127
        atomic_inc(&msg->refcnt);
128
}
129
 
130
/* Release a reference. */
131
void sctp_datamsg_put(struct sctp_datamsg *msg)
132
{
133
        if (atomic_dec_and_test(&msg->refcnt))
134
                sctp_datamsg_destroy(msg);
135
}
136
 
137
/* Free a message.  Really just give up a reference, the
138
 * really free happens in sctp_datamsg_destroy().
139
 */
140
void sctp_datamsg_free(struct sctp_datamsg *msg)
141
{
142
        sctp_datamsg_put(msg);
143
}
144
 
145
/* Hold on to all the fragments until all chunks have been sent. */
146
void sctp_datamsg_track(struct sctp_chunk *chunk)
147
{
148
        sctp_chunk_hold(chunk);
149
}
150
 
151
/* Assign a chunk to this datamsg. */
152
void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
153
{
154
        sctp_datamsg_hold(msg);
155
        chunk->msg = msg;
156
}
157
 
158
 
159
/* A data chunk can have a maximum payload of (2^16 - 20).  Break
160
 * down any such message into smaller chunks.  Opportunistically, fragment
161
 * the chunks down to the current MTU constraints.  We may get refragmented
162
 * later if the PMTU changes, but it is _much better_ to fragment immediately
163
 * with a reasonable guess than always doing our fragmentation on the
164
 * soft-interrupt.
165
 */
166
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
167
                                            struct sctp_sndrcvinfo *sinfo,
168
                                            struct msghdr *msgh, int msg_len)
169
{
170
        int max, whole, i, offset, over, err;
171
        int len, first_len;
172
        struct sctp_chunk *chunk;
173
        struct sctp_datamsg *msg;
174
        struct list_head *pos, *temp;
175
        __u8 frag;
176
 
177
        msg = sctp_datamsg_new(GFP_KERNEL);
178
        if (!msg)
179
                return NULL;
180
 
181
        /* Note: Calculate this outside of the loop, so that all fragments
182
         * have the same expiration.
183
         */
184
        if (sinfo->sinfo_timetolive) {
185
                /* sinfo_timetolive is in milliseconds */
186
                msg->expires_at = jiffies +
187
                                     SCTP_MSECS_TO_JIFFIES(sinfo->sinfo_timetolive);
188
                msg->can_expire = 1;
189
        }
190
 
191
        /* What is a reasonable fragmentation point right now? */
192
        max = asoc->pmtu;
193
        if (max < SCTP_MIN_PMTU)
194
                max = SCTP_MIN_PMTU;
195
        max -= SCTP_IP_OVERHEAD;
196
 
197
        /* Make sure not beyond maximum chunk size. */
198
        if (max > SCTP_MAX_CHUNK_LEN)
199
                max = SCTP_MAX_CHUNK_LEN;
200
 
201
        /* Subtract out the overhead of a data chunk header. */
202
        max -= sizeof(struct sctp_data_chunk);
203
        whole = 0;
204
 
205
        /* If user has specified smaller fragmentation, make it so. */
206
        if (sctp_sk(asoc->base.sk)->user_frag)
207
                max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag);
208
 
209
        first_len = max;
210
 
211
        /* Encourage Cookie-ECHO bundling. */
212
        if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
213
                whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
214
 
215
                /* Account for the DATA to be bundled with the COOKIE-ECHO. */
216
                if (whole) {
217
                        first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN;
218
                        msg_len -= first_len;
219
                        whole = 1;
220
                }
221
        }
222
 
223
        /* How many full sized?  How many bytes leftover? */
224
        whole += msg_len / max;
225
        over = msg_len % max;
226
        offset = 0;
227
 
228
        if ((whole > 1) || (whole && over))
229
                SCTP_INC_STATS_USER(SctpFragUsrMsgs);
230
 
231
        /* Create chunks for all the full sized DATA chunks. */
232
        for (i=0, len=first_len; i < whole; i++) {
233
                frag = SCTP_DATA_MIDDLE_FRAG;
234
 
235
                if (0 == i)
236
                        frag |= SCTP_DATA_FIRST_FRAG;
237
 
238
                if ((i == (whole - 1)) && !over)
239
                        frag |= SCTP_DATA_LAST_FRAG;
240
 
241
                chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
242
 
243
                if (!chunk)
244
                        goto errout;
245
                err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov);
246
                if (err < 0)
247
                        goto errout;
248
 
249
                offset += len;
250
 
251
                /* Put the chunk->skb back into the form expected by send.  */
252
                __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
253
                           - (__u8 *)chunk->skb->data);
254
 
255
                sctp_datamsg_assign(msg, chunk);
256
                list_add_tail(&chunk->frag_list, &msg->chunks);
257
 
258
                /* The first chunk, the first chunk was likely short
259
                 * to allow bundling, so reset to full size.
260
                 */
261
                if (0 == i)
262
                        len = max;
263
        }
264
 
265
        /* .. now the leftover bytes. */
266
        if (over) {
267
                if (!whole)
268
                        frag = SCTP_DATA_NOT_FRAG;
269
                else
270
                        frag = SCTP_DATA_LAST_FRAG;
271
 
272
                chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
273
 
274
                if (!chunk)
275
                        goto errout;
276
 
277
                err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov);
278
 
279
                /* Put the chunk->skb back into the form expected by send.  */
280
                __skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
281
                           - (__u8 *)chunk->skb->data);
282
                if (err < 0)
283
                        goto errout;
284
 
285
                sctp_datamsg_assign(msg, chunk);
286
                list_add_tail(&chunk->frag_list, &msg->chunks);
287
        }
288
 
289
        return msg;
290
 
291
errout:
292
        list_for_each_safe(pos, temp, &msg->chunks) {
293
                list_del_init(pos);
294
                chunk = list_entry(pos, struct sctp_chunk, frag_list);
295
                sctp_chunk_free(chunk);
296
        }
297
        sctp_datamsg_free(msg);
298
        return NULL;
299
}
300
 
301
/* Check whether this message has expired. */
302
int sctp_datamsg_expires(struct sctp_chunk *chunk)
303
{
304
        struct sctp_datamsg *msg = chunk->msg;
305
 
306
        /* FIXME: When PR-SCTP is supported we can make this
307
         * check more lenient.
308
         */
309
        if (!msg->can_expire)
310
                return 0;
311
 
312
        if (time_after(jiffies, msg->expires_at))
313
                return 1;
314
 
315
        return 0;
316
}
317
 
318
/* This chunk (and consequently entire message) has failed in its sending. */
319
void sctp_datamsg_fail(struct sctp_chunk *chunk, int error)
320
{
321
        chunk->msg->send_failed = 1;
322
        chunk->msg->send_error = error;
323
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.