10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51735Skcpoon * Common Development and Distribution License (the "License").
61735Skcpoon * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211735Skcpoon
220Sstevel@tonic-gate /*
23*13009SChandrasekar.Marimuthu@Sun.COM * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/stream.h>
280Sstevel@tonic-gate #include <sys/ddi.h>
290Sstevel@tonic-gate #include <sys/sunddi.h>
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <netinet/in.h>
320Sstevel@tonic-gate #include <netinet/ip6.h>
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <inet/common.h>
350Sstevel@tonic-gate #include <inet/ipclassifier.h>
360Sstevel@tonic-gate #include <inet/ip.h>
370Sstevel@tonic-gate #include <inet/ip6.h>
380Sstevel@tonic-gate #include <inet/mib2.h>
390Sstevel@tonic-gate #include <inet/nd.h>
400Sstevel@tonic-gate #include <inet/optcom.h>
413448Sdh155122 #include <inet/ipclassifier.h>
420Sstevel@tonic-gate #include "sctp_impl.h"
430Sstevel@tonic-gate #include "sctp_addr.h"
440Sstevel@tonic-gate
450Sstevel@tonic-gate /*ARGSUSED*/
460Sstevel@tonic-gate size_t
sctp_supaddr_param_len(sctp_t * sctp)470Sstevel@tonic-gate sctp_supaddr_param_len(sctp_t *sctp)
480Sstevel@tonic-gate {
490Sstevel@tonic-gate return (sizeof (sctp_parm_hdr_t) + sizeof (int32_t));
500Sstevel@tonic-gate }
510Sstevel@tonic-gate
520Sstevel@tonic-gate size_t
sctp_supaddr_param(sctp_t * sctp,uchar_t * p)530Sstevel@tonic-gate sctp_supaddr_param(sctp_t *sctp, uchar_t *p)
540Sstevel@tonic-gate {
550Sstevel@tonic-gate sctp_parm_hdr_t *sph;
560Sstevel@tonic-gate uint16_t *addrtype;
5711042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
580Sstevel@tonic-gate
590Sstevel@tonic-gate sph = (sctp_parm_hdr_t *)p;
600Sstevel@tonic-gate sph->sph_type = htons(PARM_SUPP_ADDRS);
610Sstevel@tonic-gate addrtype = (uint16_t *)(sph + 1);
6211042SErik.Nordmark@Sun.COM switch (connp->conn_family) {
6311042SErik.Nordmark@Sun.COM case AF_INET:
640Sstevel@tonic-gate *addrtype++ = htons(PARM_ADDR4);
650Sstevel@tonic-gate *addrtype = 0;
660Sstevel@tonic-gate sph->sph_len = htons(sizeof (*sph) + sizeof (*addrtype));
670Sstevel@tonic-gate break;
6811042SErik.Nordmark@Sun.COM case AF_INET6:
690Sstevel@tonic-gate *addrtype++ = htons(PARM_ADDR6);
700Sstevel@tonic-gate if (!sctp->sctp_connp->conn_ipv6_v6only) {
710Sstevel@tonic-gate *addrtype = htons(PARM_ADDR4);
720Sstevel@tonic-gate sph->sph_len = htons(sizeof (*sph) +
730Sstevel@tonic-gate sizeof (*addrtype) * 2);
740Sstevel@tonic-gate } else {
750Sstevel@tonic-gate *addrtype = 0;
760Sstevel@tonic-gate sph->sph_len = htons(sizeof (*sph) +
770Sstevel@tonic-gate sizeof (*addrtype));
780Sstevel@tonic-gate }
790Sstevel@tonic-gate break;
800Sstevel@tonic-gate default:
810Sstevel@tonic-gate break;
820Sstevel@tonic-gate }
830Sstevel@tonic-gate return (sizeof (*sph) + (sizeof (*addrtype) * 2));
840Sstevel@tonic-gate }
850Sstevel@tonic-gate
860Sstevel@tonic-gate /*
870Sstevel@tonic-gate * Currently, we support on PRSCTP option, there is more to come.
880Sstevel@tonic-gate */
890Sstevel@tonic-gate /*ARGSUSED*/
900Sstevel@tonic-gate size_t
sctp_options_param_len(const sctp_t * sctp,int option)910Sstevel@tonic-gate sctp_options_param_len(const sctp_t *sctp, int option)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate size_t optlen;
940Sstevel@tonic-gate
950Sstevel@tonic-gate switch (option) {
960Sstevel@tonic-gate case SCTP_PRSCTP_OPTION:
970Sstevel@tonic-gate optlen = sizeof (sctp_parm_hdr_t);
980Sstevel@tonic-gate break;
990Sstevel@tonic-gate default:
1000Sstevel@tonic-gate ASSERT(0);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate return (optlen);
1040Sstevel@tonic-gate }
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate /*ARGSUSED*/
1070Sstevel@tonic-gate size_t
sctp_options_param(const sctp_t * sctp,void * p,int option)1080Sstevel@tonic-gate sctp_options_param(const sctp_t *sctp, void *p, int option)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate sctp_parm_hdr_t *sph = (sctp_parm_hdr_t *)p;
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate switch (option) {
1130Sstevel@tonic-gate case SCTP_PRSCTP_OPTION:
1140Sstevel@tonic-gate sph->sph_type = htons(PARM_FORWARD_TSN);
1150Sstevel@tonic-gate sph->sph_len = htons(sizeof (*sph));
1160Sstevel@tonic-gate break;
1170Sstevel@tonic-gate default:
1180Sstevel@tonic-gate ASSERT(0);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate return (sizeof (*sph));
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate size_t
sctp_adaptation_code_param(sctp_t * sctp,uchar_t * p)1265586Skcpoon sctp_adaptation_code_param(sctp_t *sctp, uchar_t *p)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate sctp_parm_hdr_t *sph;
1290Sstevel@tonic-gate
1305586Skcpoon if (!sctp->sctp_send_adaptation) {
1310Sstevel@tonic-gate return (0);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate sph = (sctp_parm_hdr_t *)p;
1340Sstevel@tonic-gate sph->sph_type = htons(PARM_ADAPT_LAYER_IND);
1350Sstevel@tonic-gate sph->sph_len = htons(sizeof (*sph) + sizeof (uint32_t));
1365586Skcpoon *(uint32_t *)(sph + 1) = htonl(sctp->sctp_tx_adaptation_code);
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate return (sizeof (*sph) + sizeof (uint32_t));
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate mblk_t *
sctp_init_mp(sctp_t * sctp,sctp_faddr_t * fp)14211042SErik.Nordmark@Sun.COM sctp_init_mp(sctp_t *sctp, sctp_faddr_t *fp)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate mblk_t *mp;
1450Sstevel@tonic-gate uchar_t *p;
1460Sstevel@tonic-gate size_t initlen;
1470Sstevel@tonic-gate sctp_init_chunk_t *icp;
1480Sstevel@tonic-gate sctp_chunk_hdr_t *chp;
1490Sstevel@tonic-gate uint16_t schlen;
1500Sstevel@tonic-gate int supp_af;
15111042SErik.Nordmark@Sun.COM sctp_stack_t *sctps = sctp->sctp_sctps;
15211042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
1530Sstevel@tonic-gate
15411042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET) {
1550Sstevel@tonic-gate supp_af = PARM_SUPP_V4;
1560Sstevel@tonic-gate } else {
1570Sstevel@tonic-gate if (sctp->sctp_connp->conn_ipv6_v6only)
1580Sstevel@tonic-gate supp_af = PARM_SUPP_V6;
1590Sstevel@tonic-gate else
1600Sstevel@tonic-gate supp_af = PARM_SUPP_V6 | PARM_SUPP_V4;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate initlen = sizeof (*chp) + sizeof (*icp);
1635586Skcpoon if (sctp->sctp_send_adaptation) {
1640Sstevel@tonic-gate initlen += (sizeof (sctp_parm_hdr_t) + sizeof (uint32_t));
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate initlen += sctp_supaddr_param_len(sctp);
1673795Skcpoon initlen += sctp_addr_params(sctp, supp_af, NULL, B_TRUE);
1683448Sdh155122 if (sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled)
1690Sstevel@tonic-gate initlen += sctp_options_param_len(sctp, SCTP_PRSCTP_OPTION);
1700Sstevel@tonic-gate
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate * This could be a INIT retransmission in which case sh_verf may
1730Sstevel@tonic-gate * be non-zero, zero it out just to be sure.
1740Sstevel@tonic-gate */
1750Sstevel@tonic-gate sctp->sctp_sctph->sh_verf = 0;
1760Sstevel@tonic-gate sctp->sctp_sctph6->sh_verf = 0;
1770Sstevel@tonic-gate
17811042SErik.Nordmark@Sun.COM mp = sctp_make_mp(sctp, fp, initlen);
1791735Skcpoon if (mp == NULL) {
1803448Sdh155122 SCTP_KSTAT(sctps, sctp_send_init_failed);
1810Sstevel@tonic-gate return (NULL);
1821735Skcpoon }
18311042SErik.Nordmark@Sun.COM /* sctp_make_mp could have discovered we have no usable sources */
18411042SErik.Nordmark@Sun.COM if (sctp->sctp_nsaddrs == 0) {
18511042SErik.Nordmark@Sun.COM freemsg(mp);
18611042SErik.Nordmark@Sun.COM SCTP_KSTAT(sctps, sctp_send_init_failed);
18711042SErik.Nordmark@Sun.COM return (NULL);
18811042SErik.Nordmark@Sun.COM }
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /* Lay in a new INIT chunk, starting with the chunk header */
1910Sstevel@tonic-gate chp = (sctp_chunk_hdr_t *)mp->b_wptr;
1920Sstevel@tonic-gate chp->sch_id = CHUNK_INIT;
1930Sstevel@tonic-gate chp->sch_flags = 0;
1940Sstevel@tonic-gate schlen = (uint16_t)initlen;
1950Sstevel@tonic-gate U16_TO_ABE16(schlen, &(chp->sch_len));
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate mp->b_wptr += initlen;
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate icp = (sctp_init_chunk_t *)(chp + 1);
2000Sstevel@tonic-gate icp->sic_inittag = sctp->sctp_lvtag;
2010Sstevel@tonic-gate U32_TO_ABE32(sctp->sctp_rwnd, &(icp->sic_a_rwnd));
2020Sstevel@tonic-gate U16_TO_ABE16(sctp->sctp_num_ostr, &(icp->sic_outstr));
2030Sstevel@tonic-gate U16_TO_ABE16(sctp->sctp_num_istr, &(icp->sic_instr));
2040Sstevel@tonic-gate U32_TO_ABE32(sctp->sctp_ltsn, &(icp->sic_inittsn));
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate p = (uchar_t *)(icp + 1);
2070Sstevel@tonic-gate
2085586Skcpoon /* Adaptation layer param */
2095586Skcpoon p += sctp_adaptation_code_param(sctp, p);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate /* Add supported address types parameter */
2120Sstevel@tonic-gate p += sctp_supaddr_param(sctp, p);
2130Sstevel@tonic-gate
2140Sstevel@tonic-gate /* Add address parameters */
2153795Skcpoon p += sctp_addr_params(sctp, supp_af, p, B_FALSE);
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate /* Add Forward-TSN-Supported param */
2183448Sdh155122 if (sctp->sctp_prsctp_aware && sctps->sctps_prsctp_enabled)
2190Sstevel@tonic-gate p += sctp_options_param(sctp, p, SCTP_PRSCTP_OPTION);
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate BUMP_LOCAL(sctp->sctp_obchunks);
2220Sstevel@tonic-gate
223*13009SChandrasekar.Marimuthu@Sun.COM sctp_set_iplen(sctp, mp, fp->sf_ixa);
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate return (mp);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * Extracts the verification tag from an INIT chunk. If the INIT
2300Sstevel@tonic-gate * chunk is truncated or malformed, returns 0.
2310Sstevel@tonic-gate */
2320Sstevel@tonic-gate uint32_t
sctp_init2vtag(sctp_chunk_hdr_t * initch)2330Sstevel@tonic-gate sctp_init2vtag(sctp_chunk_hdr_t *initch)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate sctp_init_chunk_t *init;
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate init = (sctp_init_chunk_t *)(initch + 1);
2380Sstevel@tonic-gate return (init->sic_inittag);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate size_t
sctp_addr_params(sctp_t * sctp,int af,uchar_t * p,boolean_t modify)2423795Skcpoon sctp_addr_params(sctp_t *sctp, int af, uchar_t *p, boolean_t modify)
2430Sstevel@tonic-gate {
2443795Skcpoon size_t param_len;
2453795Skcpoon
2460Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs > 0);
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /*
249432Svi117747 * If we have only one local address or it is a loopback or linklocal
250432Svi117747 * association, we let the peer pull the address from the IP header.
2510Sstevel@tonic-gate */
2523795Skcpoon if ((!modify && sctp->sctp_nsaddrs == 1) || sctp->sctp_loopback ||
253432Svi117747 sctp->sctp_linklocal) {
2540Sstevel@tonic-gate return (0);
255432Svi117747 }
256432Svi117747
2573795Skcpoon param_len = sctp_saddr_info(sctp, af, p, modify);
2583795Skcpoon return ((sctp->sctp_nsaddrs == 1) ? 0 : param_len);
2590Sstevel@tonic-gate }
260