/* * Called from sctp_input_data() to add one error chunk to the error * chunks list. The error chunks list will be processed at the end * of sctp_input_data() by calling sctp_process_err(). */ void sctp_add_err(sctp_t *sctp, uint16_t serror, void *details, size_t len, sctp_faddr_t *dest) { sctp_stack_t *sctps = sctp->sctp_sctps; mblk_t *emp; uint32_t emp_len; uint32_t mss; mblk_t *sendmp; sctp_faddr_t *fp; emp = sctp_make_err(sctp, serror, details, len); if (emp == NULL) return; emp_len = MBLKL(emp); if (sctp->sctp_err_chunks != NULL) { fp = SCTP_CHUNK_DEST(sctp->sctp_err_chunks); } else { fp = dest; SCTP_SET_CHUNK_DEST(emp, dest); } mss = fp->sf_pmss; /* * If the current output packet cannot include the new error chunk, * send out the current packet and then add the new error chunk * to the new output packet. */ if (sctp->sctp_err_len + emp_len > mss) { if ((sendmp = sctp_make_mp(sctp, fp, 0)) == NULL) { SCTP_KSTAT(sctps, sctp_send_err_failed); /* Just free the latest error chunk. */ freeb(emp); return; } sendmp->b_cont = sctp->sctp_err_chunks; sctp_set_iplen(sctp, sendmp, fp->sf_ixa); (void) conn_ip_output(sendmp, fp->sf_ixa); BUMP_LOCAL(sctp->sctp_opkts); sctp->sctp_err_chunks = emp; sctp->sctp_err_len = emp_len; SCTP_SET_CHUNK_DEST(emp, dest); } else { if (sctp->sctp_err_chunks != NULL) linkb(sctp->sctp_err_chunks, emp); else sctp->sctp_err_chunks = emp; sctp->sctp_err_len += emp_len; } /* Assume that we will send it out... */ BUMP_LOCAL(sctp->sctp_obchunks); }
void sctp_wput_asconf(sctp_t *sctp, sctp_faddr_t *fp) { #define SCTP_SET_SENT_FLAG(mp) ((mp)->b_flag = SCTP_CHUNK_FLAG_SENT) mblk_t *mp; mblk_t *ipmp; uint32_t *snp; sctp_parm_hdr_t *ph; boolean_t isv4; sctp_stack_t *sctps = sctp->sctp_sctps; boolean_t saddr_set; if (sctp->sctp_cchunk_pend || sctp->sctp_cxmit_list == NULL || /* Queue it for later transmission if not yet established */ sctp->sctp_state < SCTPS_ESTABLISHED) { ip2dbg(("sctp_wput_asconf: cchunk pending? (%d) or null "\ "sctp_cxmit_list? (%s) or incorrect state? (%x)\n", sctp->sctp_cchunk_pend, sctp->sctp_cxmit_list == NULL ? "yes" : "no", sctp->sctp_state)); return; } if (fp == NULL) fp = sctp->sctp_current; /* OK to send */ ipmp = sctp_make_mp(sctp, fp, 0); if (ipmp == NULL) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); SCTP_KSTAT(sctps, sctp_send_asconf_failed); return; } mp = sctp->sctp_cxmit_list; /* Fill in the mandatory Address Parameter TLV */ isv4 = (fp != NULL) ? fp->isv4 : sctp->sctp_current->isv4; ph = (sctp_parm_hdr_t *)(mp->b_rptr + sizeof (sctp_chunk_hdr_t) + sizeof (uint32_t)); if (isv4) { ipha_t *ipha = (ipha_t *)ipmp->b_rptr; in6_addr_t ipaddr; ipaddr_t addr4; ph->sph_type = htons(PARM_ADDR4); ph->sph_len = htons(PARM_ADDR4_LEN); if (ipha->ipha_src != INADDR_ANY) { bcopy(&ipha->ipha_src, ph + 1, IP_ADDR_LEN); } else { ipaddr = sctp_get_valid_addr(sctp, B_FALSE, &saddr_set); /* * All the addresses are down. * Maybe we might have better luck next time. */ if (!saddr_set) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); freeb(ipmp); return; } IN6_V4MAPPED_TO_IPADDR(&ipaddr, addr4); bcopy(&addr4, ph + 1, IP_ADDR_LEN); } } else { ip6_t *ip6 = (ip6_t *)ipmp->b_rptr; in6_addr_t ipaddr; ph->sph_type = htons(PARM_ADDR6); ph->sph_len = htons(PARM_ADDR6_LEN); if (!IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { bcopy(&ip6->ip6_src, ph + 1, IPV6_ADDR_LEN); } else { ipaddr = sctp_get_valid_addr(sctp, B_TRUE, &saddr_set); /* * All the addresses are down. * Maybe we might have better luck next time. */ if (!saddr_set) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); freeb(ipmp); return; } bcopy(&ipaddr, ph + 1, IPV6_ADDR_LEN); } } /* Don't exceed CWND */ if ((MBLKL(mp) > (fp->cwnd - fp->suna)) || ((mp = dupb(sctp->sctp_cxmit_list)) == NULL)) { SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); freeb(ipmp); return; } /* Set the serial number now, if sending for the first time */ if (!SCTP_CHUNK_WANT_REXMIT(mp)) { snp = (uint32_t *)(mp->b_rptr + sizeof (sctp_chunk_hdr_t)); *snp = htonl(sctp->sctp_lcsn++); } SCTP_CHUNK_CLEAR_FLAGS(mp); fp->suna += MBLKL(mp); /* Attach the header and send the chunk */ ipmp->b_cont = mp; sctp->sctp_cchunk_pend = 1; SCTP_SET_SENT_FLAG(sctp->sctp_cxmit_list); SCTP_SET_CHUNK_DEST(sctp->sctp_cxmit_list, fp); sctp_set_iplen(sctp, ipmp, fp->ixa); (void) conn_ip_output(ipmp, fp->ixa); BUMP_LOCAL(sctp->sctp_opkts); SCTP_FADDR_RC_TIMER_RESTART(sctp, fp, fp->rto); #undef SCTP_SET_SENT_FLAG }
static void sctp_rc_timer(sctp_t *sctp, sctp_faddr_t *fp) { #define SCTP_CLR_SENT_FLAG(mp) ((mp)->b_flag &= ~SCTP_CHUNK_FLAG_SENT) sctp_faddr_t *nfp; sctp_faddr_t *ofp; sctp_stack_t *sctps = sctp->sctp_sctps; ASSERT(fp != NULL); fp->rc_timer_running = 0; if (sctp->sctp_state != SCTPS_ESTABLISHED || sctp->sctp_cxmit_list == NULL) { return; } /* * Not a retransmission, this was deferred due to some error * condition */ if (!SCTP_CHUNK_ISSENT(sctp->sctp_cxmit_list)) { sctp_wput_asconf(sctp, fp); return; } /* * The sent flag indicates if the msg has been sent on this fp. */ SCTP_CLR_SENT_FLAG(sctp->sctp_cxmit_list); /* Retransmission */ if (sctp->sctp_strikes >= sctp->sctp_pa_max_rxt) { /* time to give up */ BUMP_MIB(&sctps->sctps_mib, sctpAborted); sctp_assoc_event(sctp, SCTP_COMM_LOST, 0, NULL); sctp_clean_death(sctp, ETIMEDOUT); return; } if (fp->strikes >= fp->max_retr) { if (sctp_faddr_dead(sctp, fp, SCTP_FADDRS_DOWN) == -1) return; } fp->strikes++; sctp->sctp_strikes++; SCTP_CALC_RXT(sctp, fp); nfp = sctp_rotate_faddr(sctp, fp); sctp->sctp_cchunk_pend = 0; ofp = SCTP_CHUNK_DEST(sctp->sctp_cxmit_list); SCTP_SET_CHUNK_DEST(sctp->sctp_cxmit_list, NULL); ASSERT(ofp != NULL && ofp == fp); ASSERT(ofp->suna >= MBLKL(sctp->sctp_cxmit_list)); /* * Enter slow start for this destination. * XXX anything in the data path that needs to be considered? */ ofp->ssthresh = ofp->cwnd / 2; if (ofp->ssthresh < 2 * ofp->sfa_pmss) ofp->ssthresh = 2 * ofp->sfa_pmss; ofp->cwnd = ofp->sfa_pmss; ofp->pba = 0; ofp->suna -= MBLKL(sctp->sctp_cxmit_list); /* * The rexmit flags is used to determine if a serial number needs to * be assigned or not, so once set we leave it there. */ if (!SCTP_CHUNK_WANT_REXMIT(sctp->sctp_cxmit_list)) SCTP_CHUNK_REXMIT(sctp->sctp_cxmit_list); sctp_wput_asconf(sctp, nfp); #undef SCTP_CLR_SENT_FLAG }