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