sctp_output.c revision 8793b36b40d14ad0a0fecc97738dc118a928f46c
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * CDDL HEADER START
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * The contents of this file are subject to the terms of the
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * Common Development and Distribution License (the "License").
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * You may not use this file except in compliance with the License.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * See the License for the specific language governing permissions
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * and limitations under the License.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * When distributing Covered Code, include this CDDL HEADER in each
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * If applicable, add the following below this CDDL HEADER, with the
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * fields enclosed by brackets "[]" replaced with your own identifying
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * information: Portions Copyright [yyyy] [name of copyright owner]
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * CDDL HEADER END
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * Use is subject to license terms.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * PR-SCTP comments.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * A message can expire before it gets to the transmit list (i.e. it is still
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * in the unsent list - unchunked), after it gets to the transmit list, but
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * before transmission has actually started, or after transmission has begun.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * Accordingly, we check for the status of a message in sctp_chunkify() when
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * the message is being transferred from the unsent list to the transmit list;
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * in sctp_get_msg_to_send(), when we get the next chunk from the transmit
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * list and in sctp_rexmit() when we get the next chunk to be (re)transmitted.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * When we nuke a message in sctp_chunkify(), all we need to do is take it
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * out of the unsent list and update sctp_unsent; when a message is deemed
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * timed-out in sctp_get_msg_to_send() we can just take it out of the transmit
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * list, update sctp_unsent IFF transmission for the message has not yet begun
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * (i.e. !SCTP_CHUNK_ISSENT(meta->b_cont)). However, if transmission for the
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * message has started, then we cannot just take it out of the list, we need
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * to send Forward TSN chunk to the peer so that the peer can clear its
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * fragment list for this message. However, we cannot just send the Forward
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * TSN in sctp_get_msg_to_send() because there might be unacked chunks for
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * messages preceeding this abandoned message. So, we send a Forward TSN
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * IFF all messages prior to this abandoned message has been SACKd, if not
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * we defer sending the Forward TSN to sctp_cumack(), which will check for
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * this condition and send the Forward TSN via sctp_check_abandoned_msg(). In
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * sctp_rexmit() when we check for retransmissions, we need to determine if
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * the advanced peer ack point can be moved ahead, and if so, send a Forward
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * TSN to the peer instead of retransmitting the chunk. Note that when
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * we send a Forward TSN for a message, there may be yet unsent chunks for
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * this message; we need to mark all such chunks as abandoned, so that
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * sctp_cumack() can take the message out of the transmit list, additionally
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * sctp_unsent need to be adjusted. Whenever sctp_unsent is updated (i.e.
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * decremented when a message/chunk is deemed abandoned), sockfs needs to
c533a883a71cff9ff32df1c53c31201e1cbf371fhx * be notified so that it can adjust its idea of the queued message.
43439c96b8398c01c375889c79bed72d78fb4c39hx * Called to allocate a header mblk when sending data to SCTP.
43439c96b8398c01c375889c79bed72d78fb4c39hx * Data will follow in b_cont of this mblk.
43439c96b8398c01c375889c79bed72d78fb4c39hxsctp_alloc_hdr(const char *name, int nlen, const char *control, int clen,
c533a883a71cff9ff32df1c53c31201e1cbf371fhx return (mp);
c533a883a71cff9ff32df1c53c31201e1cbf371fhx/*ARGSUSED2*/
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China mp = mp->b_cont;
c533a883a71cff9ff32df1c53c31201e1cbf371fhx /* Get destination address, if specified */
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China sin6_t *sin6;
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China sin = (struct sockaddr_in *)
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China (mproto->b_rptr + tudr->DEST_offset);
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China switch (sin->sin_family) {
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China case AF_INET:
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China if (tudr->DEST_length < sizeof (*sin)) {
43439c96b8398c01c375889c79bed72d78fb4c39hx /* Ancillary Data? */
cdc64593cc1046229f4ac4daf5ead688b5efe6ebxinghua wen - Sun Microsystems - Beijing China cmsg = (struct cmsghdr *)(mproto->b_rptr + tudr->OPT_offset);
d2a61391af480de12cf4264080d7254a6de96e2apengcheng chen - Sun Microsystems - Beijing China cend = ((char *)cmsg + tudr->OPT_length);
d40f4da491abdcae192eb797766f5f44772a832fpengcheng chen - Sun Microsystems - Beijing China ASSERT(cend <= (char *)mproto->b_wptr);
c533a883a71cff9ff32df1c53c31201e1cbf371fhx for (;;) {
return (EINVAL);
if (!pump) {
return (ENOMEM);
goto process_sendq;
goto done;
goto unlock_done;
B_FALSE);
goto unlock_done;
if (msg_len == 0) {
goto unlock_done;
done:
return (error);
int count;
int chunksize;
sizeof (*sdc);
sizeof (*sdc);
int chunk_len;
goto try_next;
if (count > 0) {
count = 0;
goto next;
* about this in sctp_impl.h for SCTP_CHUNK_SENT.
next:
goto nextchunk;
if ((count > 0) &&
sizeof (*sdc);
goto nextmsg;
mblk_t *
int *error)
int hdrlen;
char *hdr;
*error = 0;
if (isv4) {
return (NULL);
return (NULL);
if (sacklen) {
if (isv4) {
return (mp);
static mblk_t *
return (fill);
return (fill);
static mblk_t *
int msglen;
int extra;
return (start_mp);
return (start_mp);
if (extra > 0) {
return (start_mp);
return (start_mp);
#ifdef DEBUG
static boolean_t
return (B_TRUE);
return (B_TRUE);
return (B_FALSE);
mblk_t *
*error = 0;
goto next_msg;
#ifdef DEBUG
return (meta);
goto next_msg;
if (*error != 0) {
#ifdef DEBUG
return (NULL);
goto next_msg;
goto chunk_done;
goto chunk_done;
#ifdef DEBUG
goto chunk_done;
goto chunkified;
#ifdef DEBUG
return (NULL);
int pktlen = 0;
int extra;
int error;
sacklen = 0;
sizeof (sctp_sack_chunk_t) +
goto unsent_data;
pad = 0;
goto unsent_data;
goto unsent_data;
goto unsent_data;
&error);
goto unsent_data;
sacklen = 0;
goto unsent_data;
goto unsent_data;
goto unsent_data;
if (extra > 0) {
goto unsent_data;
if (extra > 0) {
sctp_ftsn_sets_init(void)
NULL, 0);
sctp_ftsn_sets_fini(void)
sctp_ftsn_set_t *p;
while (s != NULL) {
p = s->next;
sctp_ftsn_set_t *p;
if (*s == NULL) {
if (*s == NULL)
return (B_FALSE);
return (B_TRUE);
return (B_TRUE);
return (B_FALSE);
return (B_FALSE);
p = p->next;
(*nsets)++;
return (B_TRUE);
mblk_t *
return (NULL);
while (nsets > 0) {
ftsn_entry++;
nsets--;
return (ftsn_mp);
if (!ubit &&
goto ftsn_done;
sacklen = 0;
sizeof (sctp_sack_chunk_t) +
sacklen = 0;
if (unsent > 0) {
int extra;
goto window_probe;
goto out;
adv_pap)) {
goto out;
goto out;
out:
if (do_ftsn) {
goto restart_timer;
goto try_bundle;
sacklen = 0;
sizeof (sctp_sack_chunk_t) +
sacklen = 0;
goto restart_timer;
if (extra > 0) {
goto restart_timer;
goto restart_timer;
sctp)) {
goto try_bundle;
if (extra > 0) {
mblk_t *
int extra;
return (NULL);
if (extra > 0) {
return (NULL);
return (NULL);
sctp)) {
goto try_bundle;
if (extra > 0) {
return (head);
int burst;
goto found_msg;
goto found_msg;