diff options
author | Erik Nordmark <Erik.Nordmark@Sun.COM> | 2009-11-11 11:49:49 -0800 |
---|---|---|
committer | Erik Nordmark <Erik.Nordmark@Sun.COM> | 2009-11-11 11:49:49 -0800 |
commit | bd670b35a010421b6e1a5536c34453a827007c81 (patch) | |
tree | 97c2057b6771dd40411a12eb89d2db2e2b2cce31 /usr/src/uts/common/inet/sctp/sctp_common.c | |
parent | b3388e4fc5f5c24c8a39fbe132a00b02dae5b717 (diff) | |
download | illumos-joyent-bd670b35a010421b6e1a5536c34453a827007c81.tar.gz |
PSARC/2009/331 IP Datapath Refactoring
PSARC/2008/522 EOF of 2001/070 IPsec HW Acceleration support
PSARC/2009/495 netstat -r flags for blackhole and reject routes
PSARC 2009/496 EOF of XRESOLV
PSARC/2009/494 IP_DONTFRAG socket option
PSARC/2009/515 fragmentation controls for ping and traceroute
6798716 ip_newroute delenda est
6798739 ARP and IP are too separate
6807265 IPv4 ip2mac() support
6756382 Please remove Venus IPsec HWACCEL code
6880632 sendto/sendmsg never returns EHOSTUNREACH in Solaris
6748582 sendmsg() return OK, but doesn't send message using IPv4-mapped x IPv6 addr
1119790 TCP and path mtu discovery
4637227 should support equal-cost multi-path (ECMP)
5078568 getsockopt() for IPV6_PATHMTU on a non-connected socket should not succeed
6419648 "AR* contract private note" should be removed as part of ATM SW EOL
6274715 Arp could keep the old entry in the cache while it waits for an arp response
6605615 Remove duplicated TCP/IP opt_set/opt_get code; use conn_t
6874677 IP_TTL can be used to send with ttl zero
4034090 arp should not let you delete your own entry
6882140 Implement IP_DONTFRAG socket option
6883858 Implement ping -D option; traceroute -F should work for IPv6 and shared-IP zones
1119792 TCP/IP black hole detection is broken on receiver
4078796 Directed broadcast forwarding code has problems
4104337 restrict the IPPROTO_IP and IPPROTO_IPV6 options based on the socket family
4203747 Source address selection for source routed packets
4230259 pmtu is increased every ip_ire_pathmtu_interval timer value.
4300533 When sticky option ipv6_pktinfo set to bogus address subsequent connect time out
4471035 ire_delete_cache_gw is called through ire_walk unnecessarily
4514572 SO_DONTROUTE socket option doesn't work with IPv6
4524980 tcp_lookup_ipv4() should compare the ifindex against tcpb->tcpb_bound_if
4532714 machine fails to switch quickly among failed default routes
4634219 IPv6 path mtu discovery is broken when using routing header
4691581 udp broadcast handling causes too many replicas
4708405 mcast is broken on machines when all interfaces are IFF_POINTOPOINT
4770457 netstat/route: source address of interface routes pretends to be gateway address
4786974 use routing table to determine routes/interface for multicast
4792619 An ip_fanout_udp_ipc_v6() routine might lead to some simpler code
4816115 Nuke ipsec_out_use_global_policy
4862844 ipsec offload corner case
4867533 tcp_rq and tcp_wq are redundant
4868589 NCEs should be shared across an IPMP group
4872093 unplumbing an improper virtual interface panics in ip_newroute_get_dst_ill()
4901671 FireEngine needs some cleanup
4907617 IPsec identity latching should be done before sending SYN-ACK
4941461 scopeid and IPV6_PKTINFO with UDP/ICMP connect() does not work properly
4944981 ip does nothing with IP6I_NEXTHOP
4963353 IPv4 and IPv6 proto fanout codes could be brought closer
4963360 consider passing zoneid using ip6i_t instead of ipsec_out_t in NDP
4963734 new ip6_asp locking is used incorrectly in ip_newroute_v6()
5008315 IPv6 code passes ip6i_t to IPsec code instead of ip6_t
5009636 memory leak in ip_fanout_proto_v6()
5092337 tcp/udp option handling can use some cleanup
5035841 Solaris can fail to create a valid broadcast ire
5043747 ar_query_xmit: Could not find the ace
5051574 tcp_check_policy is missing some checks
6305037 full hardware checksum is discarded when there're more than 2 mblks in the chain
6311149 ip.c needs to be put through a woodchipper
4708860 Unable to reassemble CGTP fragmented multicast packets
6224628 Large IPv6 packets with IPsec protection sometimes have length mismatch.
6213243 Solaris does not currently support Dead Gateway Detection
5029091 duplicate code in IP's input path for TCP/UDP/SCTP
4674643 through IPv6 CGTP routes, the very first packet is sent only after a while
6207318 Multiple default routes do not round robin connections to routers.
4823410 IP has an inconsistent view of link mtu
5105520 adding interface route to down interface causes ifconfig hang
5105707 advanced sockets API introduced some dead code
6318399 IP option handling for icmp and udp is too complicated
6321434 Every dropped packet in IP should use ip_drop_packet()
6341693 ifconfig mtu should operate on the physical interface, not individual ipif's
6352430 The credentials attached to an mblk are not particularly useful
6357894 uninitialised ipp_hoplimit needs to be cleaned up.
6363568 ip_xmit_v6() may be missing IRE releases in error cases
6364828 ip_rput_forward needs a makeover
6384416 System panics when running as multicast forwarder using multicast tunnels
6402382 TX: UDP v6 slowpath is not modified to handle mac_exempt conns
6418413 assertion failed ipha->ipha_ident == 0||ipha->ipha_ident == 0xFFFF
6420916 assertion failures in ipv6 wput path
6430851 use of b_prev to store ifindex is not 100% safe
6446106 IPv6 packets stored in nce->nce_qd_mp will be sent with incorrect tcp/udp checksums
6453711 SCTP OOTB sent as if genetated by global zone
6465212 ARP/IP merge should remove ire_freemblk.esballoc
6490163 ip_input() could misbehave if the first mblk's size is not big enough
6496664 missing ipif_refrele leads to reference leak and deferred crash in ip_wput_ipsec_out_v6
6504856 memory leak in ip_fanout_proto_v6() when using link local outer tunnel addresses
6507765 IRE cache hash function performs badly
6510186 IP_FORWARD_PROG bit is easily overlooked
6514727 cgtp ipv6 failure on snv54
6528286 MULTIRT (CGTP) should offload checksum to hardware
6533904 SCTP: doesn't support traffic class for IPv6
6539415 TX: ipif source selection is flawed for unlabeled gateways
6539851 plumbed unworking nic blocks sending broadcast packets
6564468 non-solaris SCTP stack over rawip socket: netstat command counts rawipInData not rawipOutDatagrams
6568511 ipIfStatsOutDiscards not bumped when discarding an ipsec packet on the wrong NIC
6584162 tcp_g_q_inactive() makes incorrect use of taskq_dispatch()
6603974 round-robin default with many interfaces causes infinite temporary IRE thrashing
6611750 ilm_lookup_ill_index_v4 was born an orphan
6618423 ip_wput_frag_mdt sends out packets that void pfhooks
6620964 IRE max bucket count calculations performed in ip_ire_init() are flawed
6626266 various _broadcasts seem redundant
6638182 IP_PKTINFO + SO_DONTROUTE + CIPSO IP option == panic
6647710 IPv6 possible DoS vulnerability
6657357 nce should be kmem_cache alloc'ed from an nce_cache.
6685131 ilg_add -> conn_ilg_alloc interacting with conn_ilg[] walkers can cause panic.
6730298 adding 0.0.0.0 key with mask != 0 causes 'route delete default' to fail
6730976 vni and ipv6 doesn't quite work.
6740956 assertion failed: mp->b_next == 0L && mp->b_prev == 0L in nce_queue_mp_common()
6748515 BUMP_MIB() is occasionally done on the wrong ill
6753250 ip_output_v6() `notv6' error path has an errant ill_refrele()
6756411 NULL-pointer dereference in ip_wput_local()
6769582 IP must forward packet returned from FW-HOOK
6781525 bogus usesrc usage leads directly to panic
6422839 System paniced in ip_multicast_loopback due to NULL pointer dereference
6785521 initial IPv6 DAD solicitation is dropped in ip_newroute_ipif_v6()
6787370 ipnet devices not seeing forwarded IP packets on outgoing interface
6791187 ip*dbg() calls in ip_output_options() claim to originate from ip_wput()
6794047 nce_fp_mp prevents sharing of NCEs across an IPMP group
6797926 many unnecessary ip0dbg() in ip_rput_data_v6
6846919 Packet queued for ND gets sent in the clear.
6856591 ping doesn't send packets with DF set
6861113 arp module has incorrect dependency path for hook module
6865664 IPV6_NEXTHOP does not work with TCP socket
6874681 No ICMP time exceeded when a router receives packet with ttl = 0
6880977 ip_wput_ire() uses over 1k of stack
6595433 IPsec performance could be significantly better when calling hw crypto provider synchronously
6848397 ifconfig down of an interface can hang.
6849602 IPV6_PATHMTU size issue for UDP
6885359 Add compile-time option for testing pure IPsec overhead
6889268 Odd loopback source address selection with IPMP
6895420 assertion failed: connp->conn_helper_info == NULL
6851189 Routing-related panic occurred during reboot on T2000 system running snv_117
6896174 Post-async-encryption, AH+ESP packets may have misinitialized ipha/ip6
6896687 iptun presents IPv6 with an MTU < 1280
6897006 assertion failed: ipif->ipif_id != 0 in ip_sioctl_slifzone_restart
Diffstat (limited to 'usr/src/uts/common/inet/sctp/sctp_common.c')
-rw-r--r-- | usr/src/uts/common/inet/sctp/sctp_common.c | 717 |
1 files changed, 309 insertions, 408 deletions
diff --git a/usr/src/uts/common/inet/sctp/sctp_common.c b/usr/src/uts/common/inet/sctp/sctp_common.c index 3486ba1150..b518eb3981 100644 --- a/usr/src/uts/common/inet/sctp/sctp_common.c +++ b/usr/src/uts/common/inet/sctp/sctp_common.c @@ -44,6 +44,8 @@ #include <inet/ip.h> #include <inet/ip6.h> #include <inet/ip_ire.h> +#include <inet/ip_if.h> +#include <inet/ip_ndp.h> #include <inet/mib2.h> #include <inet/nd.h> #include <inet/optcom.h> @@ -57,7 +59,7 @@ static struct kmem_cache *sctp_kmem_faddr_cache; static void sctp_init_faddr(sctp_t *, sctp_faddr_t *, in6_addr_t *, mblk_t *); -/* Set the source address. Refer to comments in sctp_get_ire(). */ +/* Set the source address. Refer to comments in sctp_get_dest(). */ void sctp_set_saddr(sctp_t *sctp, sctp_faddr_t *fp) { @@ -68,7 +70,7 @@ sctp_set_saddr(sctp_t *sctp, sctp_faddr_t *fp) /* * If there is no source address avaialble, mark this peer address * as unreachable for now. When the heartbeat timer fires, it will - * call sctp_get_ire() to re-check if there is any source address + * call sctp_get_dest() to re-check if there is any source address * available. */ if (!addr_set) @@ -76,25 +78,31 @@ sctp_set_saddr(sctp_t *sctp, sctp_faddr_t *fp) } /* - * Call this function to update the cached IRE of a peer addr fp. + * Call this function to get information about a peer addr fp. + * + * Uses ip_attr_connect to avoid explicit use of ire and source address + * selection. */ void -sctp_get_ire(sctp_t *sctp, sctp_faddr_t *fp) +sctp_get_dest(sctp_t *sctp, sctp_faddr_t *fp) { - ire_t *ire; - ipaddr_t addr4; in6_addr_t laddr; + in6_addr_t nexthop; sctp_saddr_ipif_t *sp; int hdrlen; - ts_label_t *tsl; sctp_stack_t *sctps = sctp->sctp_sctps; - ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip; + conn_t *connp = sctp->sctp_connp; + iulp_t uinfo; + uint_t pmtu; + int error; + uint32_t flags = IPDF_VERIFY_DST | IPDF_IPSEC | + IPDF_SELECT_SRC | IPDF_UNIQUE_DCE; - /* Remove the previous cache IRE */ - if ((ire = fp->ire) != NULL) { - IRE_REFRELE_NOTR(ire); - fp->ire = NULL; - } + /* + * Tell sctp_make_mp it needs to call us again should we not + * complete and set the saddr. + */ + fp->saddr = ipv6_all_zeros; /* * If this addr is not reachable, mark it as unconfirmed for now, the @@ -105,29 +113,28 @@ sctp_get_ire(sctp_t *sctp, sctp_faddr_t *fp) fp->state = SCTP_FADDRS_UNCONFIRMED; } - tsl = crgetlabel(CONN_CRED(sctp->sctp_connp)); + /* + * Socket is connected - enable PMTU discovery. + */ + if (!sctps->sctps_ignore_path_mtu) + fp->ixa->ixa_flags |= IXAF_PMTU_DISCOVERY; - if (fp->isv4) { - IN6_V4MAPPED_TO_IPADDR(&fp->faddr, addr4); - ire = ire_cache_lookup(addr4, sctp->sctp_zoneid, tsl, ipst); - if (ire != NULL) - IN6_IPADDR_TO_V4MAPPED(ire->ire_src_addr, &laddr); - } else { - ire = ire_cache_lookup_v6(&fp->faddr, sctp->sctp_zoneid, tsl, - ipst); - if (ire != NULL) - laddr = ire->ire_src_addr_v6; - } + ip_attr_nexthop(&connp->conn_xmit_ipp, fp->ixa, &fp->faddr, + &nexthop); - if (ire == NULL) { - dprint(3, ("ire2faddr: no ire for %x:%x:%x:%x\n", + laddr = fp->saddr; + error = ip_attr_connect(connp, fp->ixa, &laddr, &fp->faddr, &nexthop, + connp->conn_fport, &laddr, &uinfo, flags); + + if (error != 0) { + dprint(3, ("sctp_get_dest: no ire for %x:%x:%x:%x\n", SCTP_PRINTADDR(fp->faddr))); /* * It is tempting to just leave the src addr * unspecified and let IP figure it out, but we * *cannot* do this, since IP may choose a src addr * that is not part of this association... unless - * this sctp has bound to all addrs. So if the ire + * this sctp has bound to all addrs. So if the dest * lookup fails, try to find one in our src addr * list, unless the sctp has bound to all addrs, in * which case we change the src addr to unspec. @@ -144,56 +151,44 @@ sctp_get_ire(sctp_t *sctp, sctp_faddr_t *fp) return; goto check_current; } + ASSERT(fp->ixa->ixa_ire != NULL); + ASSERT(!(fp->ixa->ixa_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))); + + if (!sctp->sctp_loopback) + sctp->sctp_loopback = uinfo.iulp_loopback; /* Make sure the laddr is part of this association */ - if ((sp = sctp_saddr_lookup(sctp, &ire->ire_ipif->ipif_v6lcl_addr, - 0)) != NULL && !sp->saddr_ipif_dontsrc) { + if ((sp = sctp_saddr_lookup(sctp, &laddr, 0)) != NULL && + !sp->saddr_ipif_dontsrc) { if (sp->saddr_ipif_unconfirmed == 1) sp->saddr_ipif_unconfirmed = 0; + /* We did IPsec policy lookup for laddr already */ fp->saddr = laddr; } else { - dprint(2, ("ire2faddr: src addr is not part of assc\n")); + dprint(2, ("sctp_get_dest: src addr is not part of assoc " + "%x:%x:%x:%x\n", SCTP_PRINTADDR(laddr))); /* * Set the src to the first saddr and hope for the best. - * Note that we will still do the ire caching below. - * Otherwise, whenever we send a packet, we need to do - * the ire lookup again and still may not get the correct - * source address. Note that this case should very seldomly + * Note that this case should very seldomly * happen. One scenario this can happen is an app * explicitly bind() to an address. But that address is * not the preferred source address to send to the peer. */ sctp_set_saddr(sctp, fp); if (fp->state == SCTP_FADDRS_UNREACH) { - IRE_REFRELE(ire); return; } } /* - * Note that ire_cache_lookup_*() returns an ire with the tracing - * bits enabled. This requires the thread holding the ire also - * do the IRE_REFRELE(). Thus we need to do IRE_REFHOLD_NOTR() - * and then IRE_REFRELE() the ire here to make the tracing bits - * work. - */ - IRE_REFHOLD_NOTR(ire); - IRE_REFRELE(ire); - - /* Cache the IRE */ - fp->ire = ire; - if (fp->ire->ire_type == IRE_LOOPBACK && !sctp->sctp_loopback) - sctp->sctp_loopback = 1; - - /* * Pull out RTO information for this faddr and use it if we don't * have any yet. */ - if (fp->srtt == -1 && ire->ire_uinfo.iulp_rtt != 0) { + if (fp->srtt == -1 && uinfo.iulp_rtt != 0) { /* The cached value is in ms. */ - fp->srtt = MSEC_TO_TICK(ire->ire_uinfo.iulp_rtt); - fp->rttvar = MSEC_TO_TICK(ire->ire_uinfo.iulp_rtt_sd); + fp->srtt = MSEC_TO_TICK(uinfo.iulp_rtt); + fp->rttvar = MSEC_TO_TICK(uinfo.iulp_rtt_sd); fp->rto = 3 * fp->srtt; /* Bound the RTO by configured min and max values */ @@ -205,6 +200,7 @@ sctp_get_ire(sctp_t *sctp, sctp_faddr_t *fp) } SCTP_MAX_RTO(sctp, fp); } + pmtu = uinfo.iulp_mtu; /* * Record the MTU for this faddr. If the MTU for this faddr has @@ -215,9 +211,9 @@ sctp_get_ire(sctp_t *sctp, sctp_faddr_t *fp) } else { hdrlen = sctp->sctp_hdr6_len; } - if ((fp->sfa_pmss + hdrlen) != ire->ire_max_frag) { + if ((fp->sfa_pmss + hdrlen) != pmtu) { /* Make sure that sfa_pmss is a multiple of SCTP_ALIGN. */ - fp->sfa_pmss = (ire->ire_max_frag - hdrlen) & ~(SCTP_ALIGN - 1); + fp->sfa_pmss = (pmtu - hdrlen) & ~(SCTP_ALIGN - 1); if (fp->cwnd < (fp->sfa_pmss * 2)) { SET_CWND(fp, fp->sfa_pmss, sctps->sctps_slow_start_initial); @@ -230,28 +226,16 @@ check_current: } void -sctp_update_ire(sctp_t *sctp) +sctp_update_dce(sctp_t *sctp) { - ire_t *ire; sctp_faddr_t *fp; sctp_stack_t *sctps = sctp->sctp_sctps; + iulp_t uinfo; + ip_stack_t *ipst = sctps->sctps_netstack->netstack_ip; + uint_t ifindex; for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) { - if ((ire = fp->ire) == NULL) - continue; - mutex_enter(&ire->ire_lock); - - /* - * If the cached IRE is going away, there is no point to - * update it. - */ - if (ire->ire_marks & IRE_MARK_CONDEMNED) { - mutex_exit(&ire->ire_lock); - IRE_REFRELE_NOTR(ire); - fp->ire = NULL; - continue; - } - + bzero(&uinfo, sizeof (uinfo)); /* * Only record the PMTU for this faddr if we actually have * done discovery. This prevents initialized default from @@ -259,70 +243,60 @@ sctp_update_ire(sctp_t *sctp) */ if (fp->pmtu_discovered) { if (fp->isv4) { - ire->ire_max_frag = fp->sfa_pmss + + uinfo.iulp_mtu = fp->sfa_pmss + sctp->sctp_hdr_len; } else { - ire->ire_max_frag = fp->sfa_pmss + + uinfo.iulp_mtu = fp->sfa_pmss + sctp->sctp_hdr6_len; } } - if (sctps->sctps_rtt_updates != 0 && fp->rtt_updates >= sctps->sctps_rtt_updates) { /* - * If there is no old cached values, initialize them - * conservatively. Set them to be (1.5 * new value). - * This code copied from ip_ire_advise(). The cached - * value is in ms. + * dce_update_uinfo() merges these values with the + * old values. */ - if (ire->ire_uinfo.iulp_rtt != 0) { - ire->ire_uinfo.iulp_rtt = - (ire->ire_uinfo.iulp_rtt + - TICK_TO_MSEC(fp->srtt)) >> 1; - } else { - ire->ire_uinfo.iulp_rtt = - TICK_TO_MSEC(fp->srtt + (fp->srtt >> 1)); - } - if (ire->ire_uinfo.iulp_rtt_sd != 0) { - ire->ire_uinfo.iulp_rtt_sd = - (ire->ire_uinfo.iulp_rtt_sd + - TICK_TO_MSEC(fp->rttvar)) >> 1; + uinfo.iulp_rtt = TICK_TO_MSEC(fp->srtt); + uinfo.iulp_rtt_sd = TICK_TO_MSEC(fp->rttvar); + fp->rtt_updates = 0; + } + ifindex = 0; + if (IN6_IS_ADDR_LINKSCOPE(&fp->faddr)) { + /* + * If we are going to create a DCE we'd better have + * an ifindex + */ + if (fp->ixa->ixa_nce != NULL) { + ifindex = fp->ixa->ixa_nce->nce_common-> + ncec_ill->ill_phyint->phyint_ifindex; } else { - ire->ire_uinfo.iulp_rtt_sd = - TICK_TO_MSEC(fp->rttvar + - (fp->rttvar >> 1)); + continue; } - fp->rtt_updates = 0; } - mutex_exit(&ire->ire_lock); + + (void) dce_update_uinfo(&fp->faddr, ifindex, &uinfo, ipst); } } /* - * The sender must set the total length in the IP header. - * If sendto == NULL, the current will be used. + * The sender must later set the total length in the IP header. */ mblk_t * -sctp_make_mp(sctp_t *sctp, sctp_faddr_t *sendto, int trailer) +sctp_make_mp(sctp_t *sctp, sctp_faddr_t *fp, int trailer) { mblk_t *mp; size_t ipsctplen; int isv4; - sctp_faddr_t *fp; sctp_stack_t *sctps = sctp->sctp_sctps; boolean_t src_changed = B_FALSE; - ASSERT(sctp->sctp_current != NULL || sendto != NULL); - if (sendto == NULL) { - fp = sctp->sctp_current; - } else { - fp = sendto; - } + ASSERT(fp != NULL); isv4 = fp->isv4; - /* Try to look for another IRE again. */ - if (fp->ire == NULL) { - sctp_get_ire(sctp, fp); + if (SCTP_IS_ADDR_UNSPEC(isv4, fp->saddr) || + (fp->ixa->ixa_ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) { + /* Need to pick a source */ + sctp_get_dest(sctp, fp); /* * Although we still may not get an IRE, the source address * may be changed in sctp_get_ire(). Set src_changed to @@ -334,7 +308,9 @@ sctp_make_mp(sctp_t *sctp, sctp_faddr_t *sendto, int trailer) /* There is no suitable source address to use, return. */ if (fp->state == SCTP_FADDRS_UNREACH) return (NULL); - ASSERT(!SCTP_IS_ADDR_UNSPEC(fp->isv4, fp->saddr)); + + ASSERT(fp->ixa->ixa_ire != NULL); + ASSERT(!SCTP_IS_ADDR_UNSPEC(isv4, fp->saddr)); if (isv4) { ipsctplen = sctp->sctp_hdr_len; @@ -342,8 +318,7 @@ sctp_make_mp(sctp_t *sctp, sctp_faddr_t *sendto, int trailer) ipsctplen = sctp->sctp_hdr6_len; } - mp = allocb_cred(ipsctplen + sctps->sctps_wroff_xtra + trailer, - CONN_CRED(sctp->sctp_connp), sctp->sctp_cpid); + mp = allocb(ipsctplen + sctps->sctps_wroff_xtra + trailer, BPRI_MED); if (mp == NULL) { ip1dbg(("sctp_make_mp: error making mp..\n")); return (NULL); @@ -377,18 +352,6 @@ sctp_make_mp(sctp_t *sctp, sctp_faddr_t *sendto, int trailer) } } ASSERT(sctp->sctp_connp != NULL); - - /* - * IP will not free this IRE if it is condemned. SCTP needs to - * free it. - */ - if ((fp->ire != NULL) && (fp->ire->ire_marks & IRE_MARK_CONDEMNED)) { - IRE_REFRELE_NOTR(fp->ire); - fp->ire = NULL; - } - /* Stash the conn and ire ptr info. for IP */ - SCTP_STASH_IPINFO(mp, fp->ire); - return (mp); } @@ -410,17 +373,22 @@ sctp_set_ulp_prop(sctp_t *sctp) } ASSERT(sctp->sctp_ulpd); + sctp->sctp_connp->conn_wroff = sctps->sctps_wroff_xtra + hdrlen + + sizeof (sctp_data_hdr_t); + ASSERT(sctp->sctp_current->sfa_pmss == sctp->sctp_mss); bzero(&sopp, sizeof (sopp)); sopp.sopp_flags = SOCKOPT_MAXBLK|SOCKOPT_WROFF; - sopp.sopp_wroff = sctps->sctps_wroff_xtra + hdrlen + - sizeof (sctp_data_hdr_t); + sopp.sopp_wroff = sctp->sctp_connp->conn_wroff; sopp.sopp_maxblk = sctp->sctp_mss - sizeof (sctp_data_hdr_t); sctp->sctp_ulp_prop(sctp->sctp_ulpd, &sopp); } +/* + * Set the lengths in the packet and the transmit attributes. + */ void -sctp_set_iplen(sctp_t *sctp, mblk_t *mp) +sctp_set_iplen(sctp_t *sctp, mblk_t *mp, ip_xmit_attr_t *ixa) { uint16_t sum = 0; ipha_t *iph; @@ -432,19 +400,15 @@ sctp_set_iplen(sctp_t *sctp, mblk_t *mp) for (; pmp; pmp = pmp->b_cont) sum += pmp->b_wptr - pmp->b_rptr; + ixa->ixa_pktlen = sum; if (isv4) { iph = (ipha_t *)mp->b_rptr; iph->ipha_length = htons(sum); + ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr_len; } else { ip6h = (ip6_t *)mp->b_rptr; - /* - * If an ip6i_t is present, the real IPv6 header - * immediately follows. - */ - if (ip6h->ip6_nxt == IPPROTO_RAW) - ip6h = (ip6_t *)&ip6h[1]; - ip6h->ip6_plen = htons(sum - ((char *)&sctp->sctp_ip6h[1] - - sctp->sctp_iphc6)); + ip6h->ip6_plen = htons(sum - IPV6_HDR_LEN); + ixa->ixa_ip_hdr_length = sctp->sctp_ip_hdr6_len; } } @@ -501,21 +465,21 @@ sctp_add_faddr(sctp_t *sctp, in6_addr_t *addr, int sleep, boolean_t first) sctp_faddr_t *faddr; mblk_t *timer_mp; int err; + conn_t *connp = sctp->sctp_connp; if (is_system_labeled()) { - cred_t *effective_cred; + ip_xmit_attr_t *ixa = connp->conn_ixa; + ts_label_t *effective_tsl = NULL; + + ASSERT(ixa->ixa_tsl != NULL); /* * Verify the destination is allowed to receive packets * at the security label of the connection we are initiating. * - * tsol_check_dest() will create a new effective cred for + * tsol_check_dest() will create a new effective label for * this connection with a modified label or label flags only - * if there are changes from the original cred. - * - * conn_effective_cred may be non-NULL if a previous - * faddr was already added or if this is a server - * accepting a connection on a multi-label port. + * if there are changes from the original label. * * Accept whatever label we get if this is the first * destination address for this connection. The security @@ -525,27 +489,28 @@ sctp_add_faddr(sctp_t *sctp, in6_addr_t *addr, int sleep, boolean_t first) if (IN6_IS_ADDR_V4MAPPED(addr)) { uint32_t dst; IN6_V4MAPPED_TO_IPADDR(addr, dst); - err = tsol_check_dest(CONN_CRED(sctp->sctp_connp), - &dst, IPV4_VERSION, sctp->sctp_mac_mode, - &effective_cred); + err = tsol_check_dest(ixa->ixa_tsl, + &dst, IPV4_VERSION, connp->conn_mac_mode, + connp->conn_zone_is_global, &effective_tsl); } else { - err = tsol_check_dest(CONN_CRED(sctp->sctp_connp), - addr, IPV6_VERSION, sctp->sctp_mac_mode, - &effective_cred); + err = tsol_check_dest(ixa->ixa_tsl, + addr, IPV6_VERSION, connp->conn_mac_mode, + connp->conn_zone_is_global, &effective_tsl); } if (err != 0) return (err); - if (sctp->sctp_faddrs == NULL && - sctp->sctp_connp->conn_effective_cred == NULL) { - sctp->sctp_connp->conn_effective_cred = effective_cred; - } else if (effective_cred != NULL) { - crfree(effective_cred); + + if (sctp->sctp_faddrs == NULL && effective_tsl != NULL) { + ip_xmit_attr_replace_tsl(ixa, effective_tsl); + } else if (effective_tsl != NULL) { + label_rele(effective_tsl); return (EHOSTUNREACH); } } if ((faddr = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep)) == NULL) return (ENOMEM); + bzero(faddr, sizeof (*faddr)); timer_mp = sctp_timer_alloc((sctp), sctp_rexmit_timer, sleep); if (timer_mp == NULL) { kmem_cache_free(sctp_kmem_faddr_cache, faddr); @@ -553,16 +518,19 @@ sctp_add_faddr(sctp_t *sctp, in6_addr_t *addr, int sleep, boolean_t first) } ((sctpt_t *)(timer_mp->b_rptr))->sctpt_faddr = faddr; - sctp_init_faddr(sctp, faddr, addr, timer_mp); - - /* Check for subnet broadcast. */ - if (faddr->ire != NULL && faddr->ire->ire_type & IRE_BROADCAST) { - IRE_REFRELE_NOTR(faddr->ire); - sctp_timer_free(timer_mp); - faddr->timer_mp = NULL; + /* Start with any options set on the conn */ + faddr->ixa = conn_get_ixa_exclusive(connp); + if (faddr->ixa == NULL) { + freemsg(timer_mp); kmem_cache_free(sctp_kmem_faddr_cache, faddr); - return (EADDRNOTAVAIL); + return (ENOMEM); } + faddr->ixa->ixa_notify_cookie = connp->conn_sctp; + + sctp_init_faddr(sctp, faddr, addr, timer_mp); + ASSERT(faddr->ixa->ixa_cred != NULL); + + /* ip_attr_connect didn't allow broadcats/multicast dest */ ASSERT(faddr->next == NULL); if (sctp->sctp_faddrs == NULL) { @@ -644,7 +612,7 @@ sctp_redo_faddr_srcs(sctp_t *sctp) sctp_faddr_t *fp; for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) { - sctp_get_ire(sctp, fp); + sctp_get_dest(sctp, fp); } } @@ -662,15 +630,17 @@ sctp_faddr_alive(sctp_t *sctp, sctp_faddr_t *fp) fp->state = SCTP_FADDRS_ALIVE; sctp_intf_event(sctp, fp->faddr, SCTP_ADDR_AVAILABLE, 0); /* Should have a full IRE now */ - sctp_get_ire(sctp, fp); + sctp_get_dest(sctp, fp); /* * If this is the primary, switch back to it now. And * we probably want to reset the source addr used to reach * it. + * Note that if we didn't find a source in sctp_get_dest + * then we'd be unreachable at this point in time. */ - if (fp == sctp->sctp_primary) { - ASSERT(fp->state != SCTP_FADDRS_UNREACH); + if (fp == sctp->sctp_primary && + fp->state != SCTP_FADDRS_UNREACH) { sctp_set_faddr_current(sctp, fp); return; } @@ -816,9 +786,9 @@ sctp_unlink_faddr(sctp_t *sctp, sctp_faddr_t *fp) fp->rc_timer_mp = NULL; fp->rc_timer_running = 0; } - if (fp->ire != NULL) { - IRE_REFRELE_NOTR(fp->ire); - fp->ire = NULL; + if (fp->ixa != NULL) { + ixa_refrele(fp->ixa); + fp->ixa = NULL; } if (fp == sctp->sctp_faddrs) { @@ -837,7 +807,6 @@ gotit: fpp->next = fp->next; } mutex_exit(&sctp->sctp_conn_tfp->tf_lock); - /* XXX faddr2ire? */ kmem_cache_free(sctp_kmem_faddr_cache, fp); sctp->sctp_nfaddrs--; } @@ -866,8 +835,10 @@ sctp_zap_faddrs(sctp_t *sctp, int caller_holds_lock) for (fp = sctp->sctp_faddrs; fp; fp = fpn) { fpn = fp->next; - if (fp->ire != NULL) - IRE_REFRELE_NOTR(fp->ire); + if (fp->ixa != NULL) { + ixa_refrele(fp->ixa); + fp->ixa = NULL; + } kmem_cache_free(sctp_kmem_faddr_cache, fp); sctp->sctp_nfaddrs--; } @@ -888,242 +859,177 @@ sctp_zap_addrs(sctp_t *sctp) } /* - * Initialize the IPv4 header. Loses any record of any IP options. + * Build two SCTP header templates; one for IPv4 and one for IPv6. + * Store them in sctp_iphc and sctp_iphc6 respectively (and related fields). + * There are no IP addresses in the templates, but the port numbers and + * verifier are field in from the conn_t and sctp_t. + * + * Returns failure if can't allocate memory, or if there is a problem + * with a routing header/option. + * + * We allocate space for the minimum sctp header (sctp_hdr_t). + * + * We massage an routing option/header. There is no checksum implication + * for a routing header for sctp. + * + * Caller needs to update conn_wroff if desired. + * + * TSol notes: This assumes that a SCTP association has a single peer label + * since we only track a single pair of ipp_label_v4/v6 and not a separate one + * for each faddr. */ int -sctp_header_init_ipv4(sctp_t *sctp, int sleep) +sctp_build_hdrs(sctp_t *sctp, int sleep) { + conn_t *connp = sctp->sctp_connp; + ip_pkt_t *ipp = &connp->conn_xmit_ipp; + uint_t ip_hdr_length; + uchar_t *hdrs; + uint_t hdrs_len; + uint_t ulp_hdr_length = sizeof (sctp_hdr_t); + ipha_t *ipha; + ip6_t *ip6h; sctp_hdr_t *sctph; - sctp_stack_t *sctps = sctp->sctp_sctps; + in6_addr_t v6src, v6dst; + ipaddr_t v4src, v4dst; - /* - * This is a simple initialization. If there's - * already a template, it should never be too small, - * so reuse it. Otherwise, allocate space for the new one. - */ - if (sctp->sctp_iphc != NULL) { - ASSERT(sctp->sctp_iphc_len >= SCTP_MAX_COMBINED_HEADER_LENGTH); - bzero(sctp->sctp_iphc, sctp->sctp_iphc_len); - } else { - sctp->sctp_iphc_len = SCTP_MAX_COMBINED_HEADER_LENGTH; - sctp->sctp_iphc = kmem_zalloc(sctp->sctp_iphc_len, sleep); - if (sctp->sctp_iphc == NULL) { - sctp->sctp_iphc_len = 0; - return (ENOMEM); - } - } + v4src = connp->conn_saddr_v4; + v4dst = connp->conn_faddr_v4; + v6src = connp->conn_saddr_v6; + v6dst = connp->conn_faddr_v6; - sctp->sctp_ipha = (ipha_t *)sctp->sctp_iphc; + /* First do IPv4 header */ + ip_hdr_length = ip_total_hdrs_len_v4(ipp); - sctp->sctp_hdr_len = sizeof (ipha_t) + sizeof (sctp_hdr_t); - sctp->sctp_ip_hdr_len = sizeof (ipha_t); - sctp->sctp_ipha->ipha_length = htons(sizeof (ipha_t) + - sizeof (sctp_hdr_t)); - sctp->sctp_ipha->ipha_version_and_hdr_length = - (IP_VERSION << 4) | IP_SIMPLE_HDR_LENGTH_IN_WORDS; + /* In case of TX label and IP options it can be too much */ + if (ip_hdr_length > IP_MAX_HDR_LENGTH) { + /* Preserves existing TX errno for this */ + return (EHOSTUNREACH); + } + hdrs_len = ip_hdr_length + ulp_hdr_length; + ASSERT(hdrs_len != 0); - /* - * These two fields should be zero, and are already set above. - * - * sctp->sctp_ipha->ipha_ident, - * sctp->sctp_ipha->ipha_fragment_offset_and_flags. - */ + if (hdrs_len != sctp->sctp_iphc_len) { + /* Allocate new before we free any old */ + hdrs = kmem_alloc(hdrs_len, sleep); + if (hdrs == NULL) + return (ENOMEM); - sctp->sctp_ipha->ipha_ttl = sctps->sctps_ipv4_ttl; - sctp->sctp_ipha->ipha_protocol = IPPROTO_SCTP; + if (sctp->sctp_iphc != NULL) + kmem_free(sctp->sctp_iphc, sctp->sctp_iphc_len); + sctp->sctp_iphc = hdrs; + sctp->sctp_iphc_len = hdrs_len; + } else { + hdrs = sctp->sctp_iphc; + } + sctp->sctp_hdr_len = sctp->sctp_iphc_len; + sctp->sctp_ip_hdr_len = ip_hdr_length; - sctph = (sctp_hdr_t *)(sctp->sctp_iphc + sizeof (ipha_t)); + sctph = (sctp_hdr_t *)(hdrs + ip_hdr_length); sctp->sctp_sctph = sctph; - - return (0); -} - -/* - * Update sctp_sticky_hdrs based on sctp_sticky_ipp. - * The headers include ip6i_t (if needed), ip6_t, any sticky extension - * headers, and the maximum size sctp header (to avoid reallocation - * on the fly for additional sctp options). - * Returns failure if can't allocate memory. - */ -int -sctp_build_hdrs(sctp_t *sctp) -{ - char *hdrs; - uint_t hdrs_len; - ip6i_t *ip6i; - char buf[SCTP_MAX_HDR_LENGTH]; - ip6_pkt_t *ipp = &sctp->sctp_sticky_ipp; - in6_addr_t src; - in6_addr_t dst; - sctp_stack_t *sctps = sctp->sctp_sctps; - - /* - * save the existing sctp header and source/dest IP addresses - */ - bcopy(sctp->sctp_sctph6, buf, sizeof (sctp_hdr_t)); - src = sctp->sctp_ip6h->ip6_src; - dst = sctp->sctp_ip6h->ip6_dst; - hdrs_len = ip_total_hdrs_len_v6(ipp) + SCTP_MAX_HDR_LENGTH; + sctph->sh_sport = connp->conn_lport; + sctph->sh_dport = connp->conn_fport; + sctph->sh_verf = sctp->sctp_fvtag; + sctph->sh_chksum = 0; + + ipha = (ipha_t *)hdrs; + sctp->sctp_ipha = ipha; + + ipha->ipha_src = v4src; + ipha->ipha_dst = v4dst; + ip_build_hdrs_v4(hdrs, ip_hdr_length, ipp, connp->conn_proto); + ipha->ipha_length = htons(hdrs_len); + ipha->ipha_fragment_offset_and_flags = 0; + + if (ipp->ipp_fields & IPPF_IPV4_OPTIONS) + (void) ip_massage_options(ipha, connp->conn_netstack); + + /* Now IPv6 */ + ip_hdr_length = ip_total_hdrs_len_v6(ipp); + hdrs_len = ip_hdr_length + ulp_hdr_length; ASSERT(hdrs_len != 0); - if (hdrs_len > sctp->sctp_iphc6_len) { - /* Need to reallocate */ - hdrs = kmem_zalloc(hdrs_len, KM_NOSLEEP); + + if (hdrs_len != sctp->sctp_iphc6_len) { + /* Allocate new before we free any old */ + hdrs = kmem_alloc(hdrs_len, sleep); if (hdrs == NULL) return (ENOMEM); - if (sctp->sctp_iphc6_len != 0) + if (sctp->sctp_iphc6 != NULL) kmem_free(sctp->sctp_iphc6, sctp->sctp_iphc6_len); sctp->sctp_iphc6 = hdrs; sctp->sctp_iphc6_len = hdrs_len; - } - ip_build_hdrs_v6((uchar_t *)sctp->sctp_iphc6, - hdrs_len - SCTP_MAX_HDR_LENGTH, ipp, IPPROTO_SCTP); - - /* Set header fields not in ipp */ - if (ipp->ipp_fields & IPPF_HAS_IP6I) { - ip6i = (ip6i_t *)sctp->sctp_iphc6; - sctp->sctp_ip6h = (ip6_t *)&ip6i[1]; } else { - sctp->sctp_ip6h = (ip6_t *)sctp->sctp_iphc6; + hdrs = sctp->sctp_iphc6; } - /* - * sctp->sctp_ip_hdr_len will include ip6i_t if there is one. - */ - sctp->sctp_ip_hdr6_len = hdrs_len - SCTP_MAX_HDR_LENGTH; - sctp->sctp_sctph6 = (sctp_hdr_t *)(sctp->sctp_iphc6 + - sctp->sctp_ip_hdr6_len); - sctp->sctp_hdr6_len = sctp->sctp_ip_hdr6_len + sizeof (sctp_hdr_t); - - bcopy(buf, sctp->sctp_sctph6, sizeof (sctp_hdr_t)); + sctp->sctp_hdr6_len = sctp->sctp_iphc6_len; + sctp->sctp_ip_hdr6_len = ip_hdr_length; - sctp->sctp_ip6h->ip6_src = src; - sctp->sctp_ip6h->ip6_dst = dst; - /* - * If the hoplimit was not set by ip_build_hdrs_v6(), we need to - * set it to the default value for SCTP. - */ - if (!(ipp->ipp_fields & IPPF_UNICAST_HOPS)) - sctp->sctp_ip6h->ip6_hops = sctps->sctps_ipv6_hoplimit; - /* - * If we're setting extension headers after a connection - * has been established, and if we have a routing header - * among the extension headers, call ip_massage_options_v6 to - * manipulate the routing header/ip6_dst set the checksum - * difference in the sctp header template. - * (This happens in sctp_connect_ipv6 if the routing header - * is set prior to the connect.) - */ - - if ((sctp->sctp_state >= SCTPS_COOKIE_WAIT) && - (sctp->sctp_sticky_ipp.ipp_fields & IPPF_RTHDR)) { - ip6_rthdr_t *rth; - - rth = ip_find_rthdr_v6(sctp->sctp_ip6h, - (uint8_t *)sctp->sctp_sctph6); + sctph = (sctp_hdr_t *)(hdrs + ip_hdr_length); + sctp->sctp_sctph6 = sctph; + sctph->sh_sport = connp->conn_lport; + sctph->sh_dport = connp->conn_fport; + sctph->sh_verf = sctp->sctp_fvtag; + sctph->sh_chksum = 0; + + ip6h = (ip6_t *)hdrs; + sctp->sctp_ip6h = ip6h; + + ip6h->ip6_src = v6src; + ip6h->ip6_dst = v6dst; + ip_build_hdrs_v6(hdrs, ip_hdr_length, ipp, connp->conn_proto, + connp->conn_flowinfo); + ip6h->ip6_plen = htons(hdrs_len - IPV6_HDR_LEN); + + if (ipp->ipp_fields & IPPF_RTHDR) { + uint8_t *end; + ip6_rthdr_t *rth; + + end = (uint8_t *)ip6h + ip_hdr_length; + rth = ip_find_rthdr_v6(ip6h, end); if (rth != NULL) { - (void) ip_massage_options_v6(sctp->sctp_ip6h, rth, - sctps->sctps_netstack); + (void) ip_massage_options_v6(ip6h, rth, + connp->conn_netstack); } - } - return (0); -} -/* - * Initialize the IPv6 header. Loses any record of any IPv6 extension headers. - */ -int -sctp_header_init_ipv6(sctp_t *sctp, int sleep) -{ - sctp_hdr_t *sctph; - sctp_stack_t *sctps = sctp->sctp_sctps; - - /* - * This is a simple initialization. If there's - * already a template, it should never be too small, - * so reuse it. Otherwise, allocate space for the new one. - * Ensure that there is enough space to "downgrade" the sctp_t - * to an IPv4 sctp_t. This requires having space for a full load - * of IPv4 options - */ - if (sctp->sctp_iphc6 != NULL) { - ASSERT(sctp->sctp_iphc6_len >= - SCTP_MAX_COMBINED_HEADER_LENGTH); - bzero(sctp->sctp_iphc6, sctp->sctp_iphc6_len); - } else { - sctp->sctp_iphc6_len = SCTP_MAX_COMBINED_HEADER_LENGTH; - sctp->sctp_iphc6 = kmem_zalloc(sctp->sctp_iphc_len, sleep); - if (sctp->sctp_iphc6 == NULL) { - sctp->sctp_iphc6_len = 0; - return (ENOMEM); - } + /* + * Verify that the first hop isn't a mapped address. + * Routers along the path need to do this verification + * for subsequent hops. + */ + if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) + return (EADDRNOTAVAIL); } - sctp->sctp_hdr6_len = IPV6_HDR_LEN + sizeof (sctp_hdr_t); - sctp->sctp_ip_hdr6_len = IPV6_HDR_LEN; - sctp->sctp_ip6h = (ip6_t *)sctp->sctp_iphc6; - - /* Initialize the header template */ - - sctp->sctp_ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW; - sctp->sctp_ip6h->ip6_plen = ntohs(sizeof (sctp_hdr_t)); - sctp->sctp_ip6h->ip6_nxt = IPPROTO_SCTP; - sctp->sctp_ip6h->ip6_hops = sctps->sctps_ipv6_hoplimit; - - sctph = (sctp_hdr_t *)(sctp->sctp_iphc6 + IPV6_HDR_LEN); - sctp->sctp_sctph6 = sctph; - return (0); } static int -sctp_v4_label(sctp_t *sctp) +sctp_v4_label(sctp_t *sctp, sctp_faddr_t *fp) { - uchar_t optbuf[IP_MAX_OPT_LENGTH]; - const cred_t *cr = CONN_CRED(sctp->sctp_connp); - int added; + conn_t *connp = sctp->sctp_connp; - if (tsol_compute_label(cr, sctp->sctp_ipha->ipha_dst, optbuf, - sctp->sctp_sctps->sctps_netstack->netstack_ip) != 0) - return (EACCES); - - added = tsol_remove_secopt(sctp->sctp_ipha, sctp->sctp_hdr_len); - if (added == -1) - return (EACCES); - sctp->sctp_hdr_len += added; - sctp->sctp_sctph = (sctp_hdr_t *)((uchar_t *)sctp->sctp_sctph + added); - sctp->sctp_ip_hdr_len += added; - if ((sctp->sctp_v4label_len = optbuf[IPOPT_OLEN]) != 0) { - sctp->sctp_v4label_len = (sctp->sctp_v4label_len + 3) & ~3; - added = tsol_prepend_option(optbuf, sctp->sctp_ipha, - sctp->sctp_hdr_len); - if (added == -1) - return (EACCES); - sctp->sctp_hdr_len += added; - sctp->sctp_sctph = (sctp_hdr_t *)((uchar_t *)sctp->sctp_sctph + - added); - sctp->sctp_ip_hdr_len += added; - } - return (0); + ASSERT(fp->ixa->ixa_flags & IXAF_IS_IPV4); + return (conn_update_label(connp, fp->ixa, &fp->faddr, + &connp->conn_xmit_ipp)); } static int -sctp_v6_label(sctp_t *sctp) +sctp_v6_label(sctp_t *sctp, sctp_faddr_t *fp) { - uchar_t optbuf[TSOL_MAX_IPV6_OPTION]; - const cred_t *cr = CONN_CRED(sctp->sctp_connp); + conn_t *connp = sctp->sctp_connp; - if (tsol_compute_label_v6(cr, &sctp->sctp_ip6h->ip6_dst, optbuf, - sctp->sctp_sctps->sctps_netstack->netstack_ip) != 0) - return (EACCES); - if (tsol_update_sticky(&sctp->sctp_sticky_ipp, &sctp->sctp_v6label_len, - optbuf) != 0) - return (EACCES); - if (sctp_build_hdrs(sctp) != 0) - return (EACCES); - return (0); + ASSERT(!(fp->ixa->ixa_flags & IXAF_IS_IPV4)); + return (conn_update_label(connp, fp->ixa, &fp->faddr, + &connp->conn_xmit_ipp)); } /* * XXX implement more sophisticated logic + * + * Tsol note: We have already verified the addresses using tsol_check_dest + * in sctp_add_faddr, thus no need to redo that here. + * We do setup ipp_label_v4 and ipp_label_v6 based on which addresses + * we have. */ int sctp_set_hdraddrs(sctp_t *sctp) @@ -1131,50 +1037,43 @@ sctp_set_hdraddrs(sctp_t *sctp) sctp_faddr_t *fp; int gotv4 = 0; int gotv6 = 0; + conn_t *connp = sctp->sctp_connp; ASSERT(sctp->sctp_faddrs != NULL); ASSERT(sctp->sctp_nsaddrs > 0); /* Set up using the primary first */ + connp->conn_faddr_v6 = sctp->sctp_primary->faddr; + /* saddr may be unspec; make_mp() will handle this */ + connp->conn_saddr_v6 = sctp->sctp_primary->saddr; + connp->conn_laddr_v6 = connp->conn_saddr_v6; if (IN6_IS_ADDR_V4MAPPED(&sctp->sctp_primary->faddr)) { - IN6_V4MAPPED_TO_IPADDR(&sctp->sctp_primary->faddr, - sctp->sctp_ipha->ipha_dst); - /* saddr may be unspec; make_mp() will handle this */ - IN6_V4MAPPED_TO_IPADDR(&sctp->sctp_primary->saddr, - sctp->sctp_ipha->ipha_src); - if (!is_system_labeled() || sctp_v4_label(sctp) == 0) { + if (!is_system_labeled() || + sctp_v4_label(sctp, sctp->sctp_primary) == 0) { gotv4 = 1; - if (sctp->sctp_ipversion == IPV4_VERSION) { - goto copyports; + if (connp->conn_family == AF_INET) { + goto done; } } } else { - sctp->sctp_ip6h->ip6_dst = sctp->sctp_primary->faddr; - /* saddr may be unspec; make_mp() will handle this */ - sctp->sctp_ip6h->ip6_src = sctp->sctp_primary->saddr; - if (!is_system_labeled() || sctp_v6_label(sctp) == 0) + if (!is_system_labeled() || + sctp_v6_label(sctp, sctp->sctp_primary) == 0) { gotv6 = 1; + } } for (fp = sctp->sctp_faddrs; fp; fp = fp->next) { if (!gotv4 && IN6_IS_ADDR_V4MAPPED(&fp->faddr)) { - IN6_V4MAPPED_TO_IPADDR(&fp->faddr, - sctp->sctp_ipha->ipha_dst); - /* copy in the faddr_t's saddr */ - IN6_V4MAPPED_TO_IPADDR(&fp->saddr, - sctp->sctp_ipha->ipha_src); - if (!is_system_labeled() || sctp_v4_label(sctp) == 0) { + if (!is_system_labeled() || + sctp_v4_label(sctp, fp) == 0) { gotv4 = 1; - if (sctp->sctp_ipversion == IPV4_VERSION || - gotv6) { + if (connp->conn_family == AF_INET || gotv6) { break; } } } else if (!gotv6 && !IN6_IS_ADDR_V4MAPPED(&fp->faddr)) { - sctp->sctp_ip6h->ip6_dst = fp->faddr; - /* copy in the faddr_t's saddr */ - sctp->sctp_ip6h->ip6_src = fp->saddr; - if (!is_system_labeled() || sctp_v6_label(sctp) == 0) { + if (!is_system_labeled() || + sctp_v6_label(sctp, fp) == 0) { gotv6 = 1; if (gotv4) break; @@ -1182,16 +1081,10 @@ sctp_set_hdraddrs(sctp_t *sctp) } } -copyports: +done: if (!gotv4 && !gotv6) return (EACCES); - /* copy in the ports for good measure */ - sctp->sctp_sctph->sh_sport = sctp->sctp_lport; - sctp->sctp_sctph->sh_dport = sctp->sctp_fport; - - sctp->sctp_sctph6->sh_sport = sctp->sctp_lport; - sctp->sctp_sctph6->sh_dport = sctp->sctp_fport; return (0); } @@ -1343,6 +1236,7 @@ sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt, boolean_t check_saddr = B_TRUE; in6_addr_t curaddr; sctp_stack_t *sctps = sctp->sctp_sctps; + conn_t *connp = sctp->sctp_connp; if (sctp_options != NULL) *sctp_options = 0; @@ -1473,8 +1367,7 @@ sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt, if (ta == 0 || ta == INADDR_BROADCAST || ta == htonl(INADDR_LOOPBACK) || - CLASSD(ta) || - sctp->sctp_connp->conn_ipv6_v6only) { + CLASSD(ta) || connp->conn_ipv6_v6only) { goto next; } IN6_INADDR_TO_V4MAPPED((struct in_addr *) @@ -1492,7 +1385,7 @@ sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt, goto next; } } else if (ph->sph_type == htons(PARM_ADDR6) && - sctp->sctp_family == AF_INET6) { + connp->conn_family == AF_INET6) { /* An v4 socket should not take v6 addresses. */ if (remaining >= PARM_ADDR6_LEN) { in6_addr_t *addr6; @@ -1567,7 +1460,7 @@ next: } bcopy(&curaddr, dlist, sizeof (curaddr)); sctp_get_faddr_list(sctp, alist, asize); - (*cl_sctp_assoc_change)(sctp->sctp_family, alist, asize, + (*cl_sctp_assoc_change)(connp->conn_family, alist, asize, sctp->sctp_nfaddrs, dlist, dsize, 1, SCTP_CL_PADDR, (cl_sctp_handle_t)sctp); /* alist and dlist will be freed by the clustering module */ @@ -1581,7 +1474,7 @@ next: */ int sctp_secure_restart_check(mblk_t *pkt, sctp_chunk_hdr_t *ich, uint32_t ports, - int sleep, sctp_stack_t *sctps) + int sleep, sctp_stack_t *sctps, ip_recv_attr_t *ira) { sctp_faddr_t *fp, *fphead = NULL; sctp_parm_hdr_t *ph; @@ -1696,7 +1589,7 @@ sctp_secure_restart_check(mblk_t *pkt, sctp_chunk_hdr_t *ich, uint32_t ports, mutex_enter(&tf->tf_lock); for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_conn_hash_next) { - if (ports != sctp->sctp_ports) { + if (ports != sctp->sctp_connp->conn_ports) { continue; } compres = sctp_compare_faddrsets(fphead, sctp->sctp_faddrs); @@ -1776,7 +1669,8 @@ done: /* Send off the abort */ sctp_send_abort(sctp, sctp_init2vtag(ich), - SCTP_ERR_RESTART_NEW_ADDRS, dtail, dlen, pkt, 0, B_TRUE); + SCTP_ERR_RESTART_NEW_ADDRS, dtail, dlen, pkt, 0, B_TRUE, + ira); kmem_free(dtail, PARM_ADDR6_LEN * nadded); } @@ -1787,6 +1681,10 @@ cleanup: sctp_faddr_t *fpn; for (fp = fphead; fp; fp = fpn) { fpn = fp->next; + if (fp->ixa != NULL) { + ixa_refrele(fp->ixa); + fp->ixa = NULL; + } kmem_cache_free(sctp_kmem_faddr_cache, fp); } } @@ -1850,6 +1748,8 @@ sctp_init_faddr(sctp_t *sctp, sctp_faddr_t *fp, in6_addr_t *addr, { sctp_stack_t *sctps = sctp->sctp_sctps; + ASSERT(fp->ixa != NULL); + bcopy(addr, &fp->faddr, sizeof (*addr)); if (IN6_IS_ADDR_V4MAPPED(addr)) { fp->isv4 = 1; @@ -1857,11 +1757,13 @@ sctp_init_faddr(sctp_t *sctp, sctp_faddr_t *fp, in6_addr_t *addr, fp->sfa_pmss = (sctps->sctps_initial_mtu - sctp->sctp_hdr_len) & ~(SCTP_ALIGN - 1); + fp->ixa->ixa_flags |= IXAF_IS_IPV4; } else { fp->isv4 = 0; fp->sfa_pmss = (sctps->sctps_initial_mtu - sctp->sctp_hdr6_len) & ~(SCTP_ALIGN - 1); + fp->ixa->ixa_flags &= ~IXAF_IS_IPV4; } fp->cwnd = sctps->sctps_slow_start_initial * fp->sfa_pmss; fp->rto = MIN(sctp->sctp_rto_initial, sctp->sctp_init_rto_max); @@ -1884,14 +1786,13 @@ sctp_init_faddr(sctp_t *sctp, sctp_faddr_t *fp, in6_addr_t *addr, fp->df = 1; fp->pmtu_discovered = 0; fp->next = NULL; - fp->ire = NULL; fp->T3expire = 0; (void) random_get_pseudo_bytes((uint8_t *)&fp->hb_secret, sizeof (fp->hb_secret)); fp->hb_expiry = lbolt64; fp->rxt_unacked = 0; - sctp_get_ire(sctp, fp); + sctp_get_dest(sctp, fp); } /*ARGSUSED*/ |