Home | History | Annotate | Download | only in sctp
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   1735    kcpoon  * Common Development and Distribution License (the "License").
      6   1735    kcpoon  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21   1735    kcpoon 
     22      0    stevel /*
     23  11042      Erik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24      0    stevel  * Use is subject to license terms.
     25      0    stevel  */
     26      0    stevel 
     27      0    stevel #include <sys/types.h>
     28      0    stevel #include <sys/systm.h>
     29      0    stevel #include <sys/stream.h>
     30      0    stevel #include <sys/ddi.h>
     31      0    stevel #include <sys/sunddi.h>
     32      0    stevel #include <sys/strsubr.h>
     33      0    stevel #include <sys/strsun.h>
     34      0    stevel 
     35      0    stevel #include <netinet/in.h>
     36      0    stevel #include <netinet/ip6.h>
     37      0    stevel 
     38  11042      Erik #include <inet/ipsec_impl.h>
     39      0    stevel #include <inet/common.h>
     40      0    stevel #include <inet/ip.h>
     41      0    stevel #include <inet/ip6.h>
     42      0    stevel #include <inet/mib2.h>
     43      0    stevel #include <inet/nd.h>
     44      0    stevel #include <inet/optcom.h>
     45      0    stevel #include <inet/sctp_ip.h>
     46   3448  dh155122 #include <inet/ipclassifier.h>
     47      0    stevel #include "sctp_impl.h"
     48      0    stevel 
     49      0    stevel void
     50      0    stevel sctp_send_shutdown(sctp_t *sctp, int rexmit)
     51      0    stevel {
     52      0    stevel 	mblk_t *smp;
     53      0    stevel 	mblk_t *sendmp;
     54      0    stevel 	sctp_chunk_hdr_t *sch;
     55      0    stevel 	uint32_t *ctsn;
     56      0    stevel 	sctp_faddr_t *fp;
     57   3448  dh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
     58      0    stevel 
     59      0    stevel 	if (sctp->sctp_state != SCTPS_ESTABLISHED &&
     60      0    stevel 	    sctp->sctp_state != SCTPS_SHUTDOWN_PENDING &&
     61      0    stevel 	    sctp->sctp_state != SCTPS_SHUTDOWN_SENT) {
     62      0    stevel 		return;
     63      0    stevel 	}
     64      0    stevel 
     65      0    stevel 	if (sctp->sctp_state == SCTPS_ESTABLISHED) {
     66      0    stevel 		sctp->sctp_state = SCTPS_SHUTDOWN_PENDING;
     67      0    stevel 		/*
     68      0    stevel 		 * We set an upper bound on how long we will
     69      0    stevel 		 * wait for a shutdown-ack from the peer. This
     70      0    stevel 		 * is to prevent the receiver from attempting
     71      0    stevel 		 * to create a half-closed state indefinately.
     72      0    stevel 		 * See archive from IETF TSVWG mailing list
     73      0    stevel 		 * for June 2001 for more information.
     74      0    stevel 		 * Since we will not be calculating RTTs after
     75      0    stevel 		 * sending the shutdown, we can overload out_time
     76      0    stevel 		 * to track how long we have waited.
     77      0    stevel 		 */
     78  11066    rafael 		sctp->sctp_out_time = ddi_get_lbolt64();
     79      0    stevel 	}
     80      0    stevel 
     81      0    stevel 	/*
     82      0    stevel 	 * If there is unsent (or unacked) data, wait for it to get ack'd
     83      0    stevel 	 */
     84      0    stevel 	if (sctp->sctp_xmit_head != NULL || sctp->sctp_xmit_unsent != NULL) {
     85      0    stevel 		return;
     86      0    stevel 	}
     87      0    stevel 
     88      0    stevel 	/* rotate faddrs if we are retransmitting */
     89      0    stevel 	if (!rexmit) {
     90      0    stevel 		fp = sctp->sctp_current;
     91      0    stevel 	} else {
     92      0    stevel 		fp = sctp_rotate_faddr(sctp, sctp->sctp_shutdown_faddr);
     93      0    stevel 	}
     94      0    stevel 
     95      0    stevel 	sctp->sctp_shutdown_faddr = fp;
     96      0    stevel 
     97      0    stevel 	/* Link in a SACK if resending the shutdown */
     98      0    stevel 	if (sctp->sctp_state > SCTPS_SHUTDOWN_PENDING &&
     99      0    stevel 	    (sendmp = sctp_make_sack(sctp, fp, NULL)) != NULL) {
    100      0    stevel 
    101      0    stevel 		smp = allocb(sizeof (*sch) + sizeof (*ctsn), BPRI_MED);
    102      0    stevel 		if (smp == NULL) {
    103      0    stevel 			freemsg(sendmp);
    104      0    stevel 			goto done;
    105      0    stevel 		}
    106      0    stevel 		linkb(sendmp, smp);
    107      0    stevel 
    108      0    stevel 		sch = (sctp_chunk_hdr_t *)smp->b_rptr;
    109      0    stevel 		smp->b_wptr = smp->b_rptr + sizeof (*sch) + sizeof (*ctsn);
    110      0    stevel 	} else {
    111      0    stevel 		sendmp = sctp_make_mp(sctp, fp,
    112      0    stevel 		    sizeof (*sch) + sizeof (*ctsn));
    113      0    stevel 		if (sendmp == NULL) {
    114   3448  dh155122 			SCTP_KSTAT(sctps, sctp_send_shutdown_failed);
    115      0    stevel 			goto done;
    116      0    stevel 		}
    117      0    stevel 		sch = (sctp_chunk_hdr_t *)sendmp->b_wptr;
    118      0    stevel 		sendmp->b_wptr += sizeof (*sch) + sizeof (*ctsn);
    119      0    stevel 
    120      0    stevel 		/* shutdown w/o sack, update lastacked */
    121      0    stevel 		sctp->sctp_lastacked = sctp->sctp_ftsn - 1;
    122      0    stevel 	}
    123      0    stevel 
    124      0    stevel 	sch->sch_id = CHUNK_SHUTDOWN;
    125      0    stevel 	sch->sch_flags = 0;
    126      0    stevel 	sch->sch_len = htons(sizeof (*sch) + sizeof (*ctsn));
    127      0    stevel 
    128      0    stevel 	ctsn = (uint32_t *)(sch + 1);
    129      0    stevel 	*ctsn = htonl(sctp->sctp_lastacked);
    130      0    stevel 
    131      0    stevel 	/* Link the shutdown chunk in after the IP/SCTP header */
    132      0    stevel 
    133      0    stevel 	BUMP_LOCAL(sctp->sctp_obchunks);
    134      0    stevel 
    135      0    stevel 	/* Send the shutdown and restart the timer */
    136  11042      Erik 	sctp_set_iplen(sctp, sendmp, fp->ixa);
    137  11042      Erik 	(void) conn_ip_output(sendmp, fp->ixa);
    138  11042      Erik 	BUMP_LOCAL(sctp->sctp_opkts);
    139      0    stevel 
    140      0    stevel done:
    141      0    stevel 	sctp->sctp_state = SCTPS_SHUTDOWN_SENT;
    142      0    stevel 	SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current,
    143      0    stevel 	    sctp->sctp_current->rto);
    144      0    stevel }
    145      0    stevel 
    146      0    stevel int
    147   1735    kcpoon sctp_shutdown_received(sctp_t *sctp, sctp_chunk_hdr_t *sch, boolean_t crwsd,
    148   1735    kcpoon     boolean_t rexmit, sctp_faddr_t *fp)
    149      0    stevel {
    150      0    stevel 	mblk_t *samp;
    151      0    stevel 	sctp_chunk_hdr_t *sach;
    152      0    stevel 	uint32_t *tsn;
    153      0    stevel 	int trysend = 0;
    154   3448  dh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    155      0    stevel 
    156      0    stevel 	if (sctp->sctp_state != SCTPS_SHUTDOWN_ACK_SENT)
    157      0    stevel 		sctp->sctp_state = SCTPS_SHUTDOWN_RECEIVED;
    158      0    stevel 
    159      0    stevel 	/* Extract and process the TSN in the shutdown chunk */
    160      0    stevel 	if (sch != NULL) {
    161      0    stevel 		tsn = (uint32_t *)(sch + 1);
    162      0    stevel 		trysend = sctp_cumack(sctp, ntohl(*tsn), &samp);
    163      0    stevel 	}
    164      0    stevel 
    165      0    stevel 	/* Don't allow sending new data */
    166   4818    kcpoon 	if (!SCTP_IS_DETACHED(sctp) && !sctp->sctp_ulp_discon_done) {
    167   8348      Eric 		sctp->sctp_ulp_opctl(sctp->sctp_ulpd, SOCK_OPCTL_SHUT_SEND, 0);
    168   4818    kcpoon 		sctp->sctp_ulp_discon_done = B_TRUE;
    169   4818    kcpoon 	}
    170      0    stevel 
    171      0    stevel 	/*
    172      0    stevel 	 * If there is unsent or unacked data, try sending them out now.
    173      0    stevel 	 * The other side should acknowledge them.  After we have flushed
    174      0    stevel 	 * the transmit queue, we can complete the shutdown sequence.
    175      0    stevel 	 */
    176      0    stevel 	if (sctp->sctp_xmit_head != NULL || sctp->sctp_xmit_unsent != NULL)
    177      0    stevel 		return (1);
    178      0    stevel 
    179   1735    kcpoon 	if (fp == NULL) {
    180   1735    kcpoon 		/* rotate faddrs if we are retransmitting */
    181   1735    kcpoon 		if (!rexmit)
    182   1735    kcpoon 			fp = sctp->sctp_current;
    183   1735    kcpoon 		else
    184   1735    kcpoon 			fp = sctp_rotate_faddr(sctp, sctp->sctp_shutdown_faddr);
    185   1735    kcpoon 	}
    186   1735    kcpoon 	sctp->sctp_shutdown_faddr = fp;
    187      0    stevel 
    188      0    stevel 	samp = sctp_make_mp(sctp, fp, sizeof (*sach));
    189   1735    kcpoon 	if (samp == NULL) {
    190   3448  dh155122 		SCTP_KSTAT(sctps, sctp_send_shutdown_ack_failed);
    191      0    stevel 		goto dotimer;
    192   1735    kcpoon 	}
    193      0    stevel 
    194      0    stevel 	sach = (sctp_chunk_hdr_t *)samp->b_wptr;
    195      0    stevel 	sach->sch_id = CHUNK_SHUTDOWN_ACK;
    196      0    stevel 	sach->sch_flags = 0;
    197      0    stevel 	sach->sch_len = htons(sizeof (*sach));
    198      0    stevel 
    199      0    stevel 	samp->b_wptr += sizeof (*sach);
    200      0    stevel 
    201      0    stevel 	/*
    202      0    stevel 	 * bundle a "cookie received while shutting down" error if
    203      0    stevel 	 * the caller asks for it.
    204      0    stevel 	 */
    205      0    stevel 	if (crwsd) {
    206      0    stevel 		mblk_t *errmp;
    207      0    stevel 
    208      0    stevel 		errmp = sctp_make_err(sctp, SCTP_ERR_COOKIE_SHUT, NULL, 0);
    209      0    stevel 		if (errmp != NULL) {
    210      0    stevel 			linkb(samp, errmp);
    211      0    stevel 			BUMP_LOCAL(sctp->sctp_obchunks);
    212      0    stevel 		}
    213      0    stevel 	}
    214      0    stevel 
    215      0    stevel 	BUMP_LOCAL(sctp->sctp_obchunks);
    216      0    stevel 
    217  11042      Erik 	sctp_set_iplen(sctp, samp, fp->ixa);
    218  11042      Erik 	(void) conn_ip_output(samp, fp->ixa);
    219  11042      Erik 	BUMP_LOCAL(sctp->sctp_opkts);
    220      0    stevel 
    221      0    stevel dotimer:
    222      0    stevel 	sctp->sctp_state = SCTPS_SHUTDOWN_ACK_SENT;
    223      0    stevel 	SCTP_FADDR_TIMER_RESTART(sctp, sctp->sctp_current,
    224      0    stevel 	    sctp->sctp_current->rto);
    225      0    stevel 
    226      0    stevel 	return (trysend);
    227      0    stevel }
    228      0    stevel 
    229      0    stevel void
    230      0    stevel sctp_shutdown_complete(sctp_t *sctp)
    231      0    stevel {
    232      0    stevel 	mblk_t *scmp;
    233      0    stevel 	sctp_chunk_hdr_t *scch;
    234   3448  dh155122 	sctp_stack_t	*sctps = sctp->sctp_sctps;
    235      0    stevel 
    236  11042      Erik 	scmp = sctp_make_mp(sctp, sctp->sctp_current, sizeof (*scch));
    237      0    stevel 	if (scmp == NULL) {
    238      0    stevel 		/* XXX use timer approach */
    239   3448  dh155122 		SCTP_KSTAT(sctps, sctp_send_shutdown_comp_failed);
    240      0    stevel 		return;
    241      0    stevel 	}
    242      0    stevel 
    243      0    stevel 	scch = (sctp_chunk_hdr_t *)scmp->b_wptr;
    244      0    stevel 	scch->sch_id = CHUNK_SHUTDOWN_COMPLETE;
    245      0    stevel 	scch->sch_flags = 0;
    246      0    stevel 	scch->sch_len = htons(sizeof (*scch));
    247      0    stevel 
    248      0    stevel 	scmp->b_wptr += sizeof (*scch);
    249      0    stevel 
    250      0    stevel 	BUMP_LOCAL(sctp->sctp_obchunks);
    251      0    stevel 
    252  11042      Erik 	sctp_set_iplen(sctp, scmp, sctp->sctp_current->ixa);
    253  11042      Erik 	(void) conn_ip_output(scmp, sctp->sctp_current->ixa);
    254  11042      Erik 	BUMP_LOCAL(sctp->sctp_opkts);
    255      0    stevel }
    256      0    stevel 
    257      0    stevel /*
    258      0    stevel  * Similar to sctp_shutdown_complete(), except that since this
    259      0    stevel  * is out-of-the-blue, we can't use an sctp's association information,
    260      0    stevel  * and instead must draw all necessary info from the incoming packet.
    261      0    stevel  */
    262      0    stevel void
    263  11042      Erik sctp_ootb_shutdown_ack(mblk_t *mp, uint_t ip_hdr_len, ip_recv_attr_t *ira,
    264  11042      Erik     ip_stack_t *ipst)
    265      0    stevel {
    266      0    stevel 	boolean_t		isv4;
    267  11042      Erik 	ipha_t			*ipha = NULL;
    268  11042      Erik 	ip6_t			*ip6h = NULL;
    269      0    stevel 	sctp_hdr_t		*insctph;
    270      0    stevel 	sctp_chunk_hdr_t	*scch;
    271      0    stevel 	int			i;
    272      0    stevel 	uint16_t		port;
    273      0    stevel 	mblk_t			*mp1;
    274  11042      Erik 	netstack_t		*ns = ipst->ips_netstack;
    275  11042      Erik 	sctp_stack_t		*sctps = ns->netstack_sctp;
    276  11042      Erik 	ip_xmit_attr_t		ixas;
    277      0    stevel 
    278  11042      Erik 	bzero(&ixas, sizeof (ixas));
    279      0    stevel 
    280  11042      Erik 	isv4 = (IPH_HDR_VERSION(mp->b_rptr) == IPV4_VERSION);
    281  11042      Erik 
    282  11042      Erik 	ASSERT(MBLKL(mp) >= sizeof (*insctph) + sizeof (*scch) +
    283  11042      Erik 	    (isv4 ? sizeof (ipha_t) : sizeof (ip6_t)));
    284      0    stevel 
    285      0    stevel 	/*
    286      0    stevel 	 * Check to see if we can reuse the incoming mblk.  There should
    287  11042      Erik 	 * not be other reference. Since this packet comes from below,
    288      0    stevel 	 * there should be enough header space to fill in what the lower
    289  11042      Erik 	 * layers want to add.
    290      0    stevel 	 */
    291  11042      Erik 	if (DB_REF(mp) != 1) {
    292  11042      Erik 		mp1 = allocb(MBLKL(mp) + sctps->sctps_wroff_xtra, BPRI_MED);
    293      0    stevel 		if (mp1 == NULL) {
    294  11042      Erik 			freeb(mp);
    295      0    stevel 			return;
    296      0    stevel 		}
    297   3448  dh155122 		mp1->b_rptr += sctps->sctps_wroff_xtra;
    298  11042      Erik 		mp1->b_wptr = mp1->b_rptr + MBLKL(mp);
    299  11042      Erik 		bcopy(mp->b_rptr, mp1->b_rptr, MBLKL(mp));
    300  11042      Erik 		freeb(mp);
    301  11042      Erik 		mp = mp1;
    302   1932  vi117747 	} else {
    303  11042      Erik 		DB_CKSUMFLAGS(mp) = 0;
    304      0    stevel 	}
    305      0    stevel 
    306  11042      Erik 	ixas.ixa_pktlen = ip_hdr_len + sizeof (*insctph) + sizeof (*scch);
    307  11042      Erik 	ixas.ixa_ip_hdr_length = ip_hdr_len;
    308      0    stevel 	/*
    309      0    stevel 	 * We follow the logic in tcp_xmit_early_reset() in that we skip
    310  11042      Erik 	 * reversing source route (i.e. replace all IP options with EOL).
    311      0    stevel 	 */
    312      0    stevel 	if (isv4) {
    313      0    stevel 		ipaddr_t	v4addr;
    314      0    stevel 
    315  11042      Erik 		ipha = (ipha_t *)mp->b_rptr;
    316      0    stevel 		for (i = IP_SIMPLE_HDR_LENGTH; i < (int)ip_hdr_len; i++)
    317  11042      Erik 			mp->b_rptr[i] = IPOPT_EOL;
    318      0    stevel 		/* Swap addresses */
    319  11042      Erik 		ipha->ipha_length = htons(ixas.ixa_pktlen);
    320  11042      Erik 		v4addr = ipha->ipha_src;
    321  11042      Erik 		ipha->ipha_src = ipha->ipha_dst;
    322  11042      Erik 		ipha->ipha_dst = v4addr;
    323  11042      Erik 		ipha->ipha_ident = 0;
    324  11042      Erik 		ipha->ipha_ttl = (uchar_t)sctps->sctps_ipv4_ttl;
    325  11042      Erik 
    326  11042      Erik 		ixas.ixa_flags = IXAF_BASIC_SIMPLE_V4;
    327      0    stevel 	} else {
    328      0    stevel 		in6_addr_t	v6addr;
    329      0    stevel 
    330  11042      Erik 		ip6h = (ip6_t *)mp->b_rptr;
    331      0    stevel 		/* Remove any extension headers assuming partial overlay */
    332      0    stevel 		if (ip_hdr_len > IPV6_HDR_LEN) {
    333      0    stevel 			uint8_t	*to;
    334      0    stevel 
    335  11042      Erik 			to = mp->b_rptr + ip_hdr_len - IPV6_HDR_LEN;
    336  11042      Erik 			ovbcopy(ip6h, to, IPV6_HDR_LEN);
    337  11042      Erik 			mp->b_rptr += ip_hdr_len - IPV6_HDR_LEN;
    338      0    stevel 			ip_hdr_len = IPV6_HDR_LEN;
    339  11042      Erik 			ip6h = (ip6_t *)mp->b_rptr;
    340  11042      Erik 			ip6h->ip6_nxt = IPPROTO_SCTP;
    341      0    stevel 		}
    342  11042      Erik 		ip6h->ip6_plen = htons(ixas.ixa_pktlen - IPV6_HDR_LEN);
    343  11042      Erik 		v6addr = ip6h->ip6_src;
    344  11042      Erik 		ip6h->ip6_src = ip6h->ip6_dst;
    345  11042      Erik 		ip6h->ip6_dst = v6addr;
    346  11042      Erik 		ip6h->ip6_hops = (uchar_t)sctps->sctps_ipv6_hoplimit;
    347  11042      Erik 
    348  11042      Erik 		ixas.ixa_flags = IXAF_BASIC_SIMPLE_V6;
    349  11042      Erik 		if (IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_dst)) {
    350  11042      Erik 			ixas.ixa_flags |= IXAF_SCOPEID_SET;
    351  11042      Erik 			ixas.ixa_scopeid = ira->ira_ruifindex;
    352  11042      Erik 		}
    353      0    stevel 	}
    354  11042      Erik 
    355  11042      Erik 	insctph = (sctp_hdr_t *)(mp->b_rptr + ip_hdr_len);
    356      0    stevel 
    357      0    stevel 	/* Swap ports.  Verification tag is reused. */
    358      0    stevel 	port = insctph->sh_sport;
    359      0    stevel 	insctph->sh_sport = insctph->sh_dport;
    360      0    stevel 	insctph->sh_dport = port;
    361      0    stevel 
    362      0    stevel 	/* Lay in the shutdown complete chunk */
    363      0    stevel 	scch = (sctp_chunk_hdr_t *)(insctph + 1);
    364      0    stevel 	scch->sch_id = CHUNK_SHUTDOWN_COMPLETE;
    365      0    stevel 	scch->sch_len = htons(sizeof (*scch));
    366      0    stevel 	scch->sch_flags = 0;
    367      0    stevel 
    368      0    stevel 	/* Set the T-bit */
    369      0    stevel 	SCTP_SET_TBIT(scch);
    370      0    stevel 
    371  11042      Erik 	ixas.ixa_protocol = IPPROTO_SCTP;
    372  11042      Erik 	ixas.ixa_zoneid = ira->ira_zoneid;
    373  11042      Erik 	ixas.ixa_ipst = ipst;
    374  11042      Erik 	ixas.ixa_ifindex = 0;
    375      0    stevel 
    376  11042      Erik 	if (ira->ira_flags & IRAF_IPSEC_SECURE) {
    377  11042      Erik 		/*
    378  11042      Erik 		 * Apply IPsec based on how IPsec was applied to
    379  11042      Erik 		 * the packet that was out of the blue.
    380  11042      Erik 		 */
    381  11042      Erik 		if (!ipsec_in_to_out(ira, &ixas, mp, ipha, ip6h)) {
    382  11042      Erik 			BUMP_MIB(&ipst->ips_ip_mib, ipIfStatsOutDiscards);
    383  11042      Erik 			/* Note: mp already consumed and ip_drop_packet done */
    384  11042      Erik 			return;
    385  11042      Erik 		}
    386  11042      Erik 	} else {
    387  11042      Erik 		/*
    388  11042      Erik 		 * This is in clear. The message we are building
    389  11042      Erik 		 * here should go out in clear, independent of our policy.
    390  11042      Erik 		 */
    391  11042      Erik 		ixas.ixa_flags |= IXAF_NO_IPSEC;
    392  11042      Erik 	}
    393  11042      Erik 
    394  11042      Erik 	(void) ip_output_simple(mp, &ixas);
    395  11042      Erik 	ixa_cleanup(&ixas);
    396      0    stevel }
    397