diff options
author | rrs <rrs@FreeBSD.org> | 2007-05-08 00:21:05 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-05-08 00:21:05 +0000 |
commit | 532412f6c49a9077f90f5cd40b66c87a16efe085 (patch) | |
tree | 4db56edaf6063ffdff843e7c1228529525ec2e80 /sys/netinet/sctputil.c | |
parent | caa15fdaeb248ba5c8dd136083da6989cacd1979 (diff) | |
download | FreeBSD-src-532412f6c49a9077f90f5cd40b66c87a16efe085.zip FreeBSD-src-532412f6c49a9077f90f5cd40b66c87a16efe085.tar.gz |
- More macros for OS compatabilty
- PR-SCTP would ignore FWD-TSN's above a rwnd's worth
of TSN's (1 byte msgs).. this left the peer hopelessly
out of sync.. or an attacker. So now we abort the assoc.
- New IFN hash, also rename hashes to match addr/ifn now
that the vrf has multiple.
- Do not enable SCTP_PCB_FLAGS_RECVDATAIOEVNT per default
as defined in the Socket API ID.
- Export MTU information via sysctl.
- Vrf's need table id's. This is default for
BSD, but may be other things later when BSD
fully supports VRFs.
- Additional stream reset bug (caught by cisco dev-test).
- Additional validations for the address in sending a message (socket api).
-------- and -----
- Fix association notifications not to give the active open
side false notifications.
- Fix so sendfile and SENDALL will work properly (missing
flag to say socket sender is done).
- Fix Bug that prevented COOKIES from being retransmitted.
- Break out connectx into helper sub-models so that iox routines can
reuse the helpers.
- When an address is added during system init (non-dynamic mode) make
sure that the "defer use" flag is not set.
** its compiling on XR now :-D **
Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctputil.c')
-rw-r--r-- | sys/netinet/sctputil.c | 469 |
1 files changed, 254 insertions, 215 deletions
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index a489184..c9b422e 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -837,7 +837,7 @@ sctp_fill_random_store(struct sctp_pcb *m) * our counter. The result becomes our good random numbers and we * then setup to give these out. Note that we do no locking to * protect this. This is ok, since if competing folks call this we - * will get more gobbled gook in the random store whic is what we + * will get more gobbled gook in the random store which is what we * want. There is a danger that two guys will use the same random * numbers, but thats ok too since that is random as well :-> */ @@ -1025,6 +1025,10 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_association *asoc, asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(m->sctp_socket); asoc->smallest_mtu = m->sctp_frag_point; +#ifdef SCTP_PRINT_FOR_B_AND_M + printf("smallest_mtu init'd with asoc to :%d\n", + asoc->smallest_mtu); +#endif asoc->minrto = m->sctp_ep.sctp_minrto; asoc->maxrto = m->sctp_ep.sctp_maxrto; @@ -2424,6 +2428,10 @@ sctp_mtu_size_reset(struct sctp_inpcb *inp, struct sctp_tmit_chunk *chk; unsigned int eff_mtu, ovh; +#ifdef SCTP_PRINT_FOR_B_AND_M + printf("sctp_mtu_size_reset(%p, asoc:%p mtu:%d\n", + inp, asoc, mtu); +#endif asoc->smallest_mtu = mtu; if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { ovh = SCTP_MIN_OVERHEAD; @@ -3207,6 +3215,15 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, /* Can't send up to a closed socket any notifications */ return; } + if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || + (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) { + if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || + (notification == SCTP_NOTIFY_INTERFACE_UP) || + (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { + /* Don't report these in front states */ + return; + } + } if (stcb && (stcb->asoc.assoc_up_sent == 0) && (notification != SCTP_NOTIFY_ASSOC_UP)) { if ((notification != SCTP_NOTIFY_ASSOC_DOWN) && (notification != SCTP_NOTIFY_ASSOC_ABORTED) && @@ -3478,7 +3495,8 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error) void sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, - struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err) + struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err, + uint32_t vrf_id, uint32_t table_id) { uint32_t vtag; @@ -3487,8 +3505,11 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, /* We have a TCB to abort, send notification too */ vtag = stcb->asoc.peer_vtag; sctp_abort_notification(stcb, 0); + /* get the assoc vrf id and table id */ + vrf_id = stcb->asoc.vrf_id; + table_id = stcb->asoc.table_id; } - sctp_send_abort(m, iphlen, sh, vtag, op_err); + sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id, table_id); if (stcb != NULL) { /* Ok, now lets free it */ sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4); @@ -3597,7 +3618,8 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh, - struct sctp_inpcb *inp, struct mbuf *op_err) + struct sctp_inpcb *inp, struct mbuf *op_err, uint32_t vrf_id, + uint32_t table_id) { struct sctp_chunkhdr *ch, chunk_buf; unsigned int chk_length; @@ -3631,7 +3653,8 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh, */ return; case SCTP_SHUTDOWN_ACK: - sctp_send_shutdown_complete2(m, iphlen, sh); + sctp_send_shutdown_complete2(m, iphlen, sh, vrf_id, + table_id); return; default: break; @@ -3640,7 +3663,7 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh, ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), (uint8_t *) & chunk_buf); } - sctp_send_abort(m, iphlen, sh, 0, op_err); + sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id, table_id); } /* @@ -3996,7 +4019,10 @@ sctp_add_to_readq(struct sctp_inpcb *inp, TAILQ_INSERT_TAIL(&inp->read_queue, control, next); SCTP_INP_READ_UNLOCK(inp); if (inp && inp->sctp_socket) { - sctp_sorwakeup(inp, inp->sctp_socket); + if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { + SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); + } else + sctp_sorwakeup(inp, inp->sctp_socket); } } @@ -4114,7 +4140,10 @@ get_out: SCTP_INP_READ_UNLOCK(inp); } if (inp && inp->sctp_socket) { - sctp_sorwakeup(inp, inp->sctp_socket); + if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { + SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); + } else + sctp_sorwakeup(inp, inp->sctp_socket); } return (0); } @@ -4333,11 +4362,11 @@ sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) } hash_of_addr = sctp_get_ifa_hash_val(addr); - hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_hashmark)]; + hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; if (hash_head == NULL) { printf("hash_of_addr:%x mask:%x table:%x - ", - (u_int)hash_of_addr, (u_int)vrf->vrf_hashmark, - (u_int)(hash_of_addr & vrf->vrf_hashmark)); + (u_int)hash_of_addr, (u_int)vrf->vrf_addr_hashmark, + (u_int)(hash_of_addr & vrf->vrf_addr_hashmark)); sctp_print_address(addr); printf("No such bucket for address\n"); if (holds_lock == 0) @@ -4519,6 +4548,9 @@ sctp_sorecvmsg(struct socket *so, int held_length = 0; int sockbuf_lock = 0; + if (uio == NULL) { + return (EINVAL); + } if (msg_flags) { in_flags = *msg_flags; if (in_flags & MSG_PEEK) @@ -4526,8 +4558,8 @@ sctp_sorecvmsg(struct socket *so, } else { in_flags = 0; } - if (uio) - slen = uio->uio_resid; + slen = uio->uio_resid; + /* Pull in and set up our int flags */ if (in_flags & MSG_OOB) { /* Out of band's NOT supported */ @@ -4554,11 +4586,11 @@ sctp_sorecvmsg(struct socket *so, in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); #ifdef SCTP_RECV_RWND_LOGGING sctp_misc_ints(SCTP_SORECV_ENTER, - rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, slen); + rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid); #endif #ifdef SCTP_RECV_RWND_LOGGING sctp_misc_ints(SCTP_SORECV_ENTERPL, - rwnd_req, block_allowed, so->so_rcv.sb_cc, slen); + rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid); #endif @@ -4593,7 +4625,7 @@ restart_nosblocks: /* we need to wait for data */ #ifdef SCTP_RECV_DETAIL_RWND_LOGGING sctp_misc_ints(SCTP_SORECV_BLOCKSA, - 0, 0, so->so_rcv.sb_cc, slen); + 0, 0, so->so_rcv.sb_cc, uio->uio_resid); #endif if ((so->so_rcv.sb_cc == 0) && ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -4768,7 +4800,7 @@ restart_nosblocks: while (ctl) { if ((ctl->stcb != control->stcb) && (ctl->length) && (ctl->some_taken || - (ctl->spec_flags & M_NOTIFICATION) || + (ctl->spec_flags & M_NOTIFICATION) || ((ctl->do_not_ref_stcb == 0) && (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) ) { @@ -4776,7 +4808,8 @@ restart_nosblocks: * If we have a different TCB next, and there is data * present. If we have already taken some (pdapi), OR we can * ref the tcb and no delivery as started on this stream, we - * take it. + * take it. Note we allow a notification on a different + * assoc to be delivered.. */ control = ctl; goto found_one; @@ -4784,7 +4817,7 @@ restart_nosblocks: (ctl->length) && ((ctl->some_taken) || ((ctl->do_not_ref_stcb == 0) && -- ((ctl->spec_flags & M_NOTIFICATION) == 0) && + ((ctl->spec_flags & M_NOTIFICATION) == 0) && (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) ) { /*- @@ -4792,6 +4825,8 @@ restart_nosblocks: * have the strm interleave feature present. Then if we have * taken some (pdapi) or we can refer to tht tcb AND we have * not started a delivery for this stream, we can take it. + * Note we do NOT allow a notificaiton on the same assoc to + * be delivered. */ control = ctl; goto found_one; @@ -4855,8 +4890,8 @@ found_one: stcb->freed_by_sorcv_sincelast = 0; } } - if (stcb && - ((control->spec_flags & M_NOTIFICATION) == 0) && + if (stcb && + ((control->spec_flags & M_NOTIFICATION) == 0) && control->do_not_ref_stcb == 0) { stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; } @@ -5188,6 +5223,10 @@ get_more_data: control->held_length = 0; wakeup_read_socket = 1; } + if (control->aux_data) { + sctp_m_free(control->aux_data); + control->aux_data = NULL; + } no_rcv_needed = control->do_not_ref_stcb; sctp_free_remote_addr(control->whoFrom); control->data = NULL; @@ -5325,199 +5364,48 @@ wait_some_more: } goto get_more_data; } else { - /* copy out the mbuf chain */ -get_more_data2: - /* - * Do we have a uio, I doubt it if so we grab the size from - * it, if not you get it all + /*- + * Give caller back the mbuf chain, + * store in uio_resid the length */ - if (uio) - cp_len = uio->uio_resid; - else - cp_len = control->length; - - if ((uint32_t) cp_len >= control->length) { - /* easy way */ - if ((control->end_added == 0) || - (TAILQ_NEXT(control, next) == NULL)) { - /* Need to get rlock */ - if (hold_rlock == 0) { - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - } - } - if (control->end_added) { - out_flags |= MSG_EOR; - if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; - } - if (control->spec_flags & M_NOTIFICATION) { - out_flags |= MSG_NOTIFICATION; - } - if (uio) - uio->uio_resid -= control->length; - *mp = control->data; - m = control->data; - while (m) { -#ifdef SCTP_SB_LOGGING - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); -#endif - sctp_sbfree(control, stcb, &so->so_rcv, m); - freed_so_far += SCTP_BUF_LEN(m); -#ifdef SCTP_SB_LOGGING - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); -#endif - m = SCTP_BUF_NEXT(m); - } - control->data = control->tail_mbuf = NULL; - control->length = 0; - if (out_flags & MSG_EOR) { - /* Done with this control */ - goto done_with_control; - } - /* still more to do with this conntrol */ - /* do we really support msg_waitall here? */ - if ((block_allowed == 0) || - ((in_flags & MSG_WAITALL) == 0)) { - goto release; - } - wait_some_more2: - if (so->so_rcv.sb_state & SBS_CANTRCVMORE) - goto release; - if (hold_rlock == 1) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } - if (hold_sblock == 0) { - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; - } - if (so->so_rcv.sb_cc <= control->held_length) { - error = sbwait(&so->so_rcv); - if (error) { - goto release; - } - } - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } - if (control->length == 0) { - /* still nothing here */ - if (control->end_added == 1) { - /* - * he aborted, or is done i.e. - * shutdown - */ - out_flags |= MSG_EOR; - if (control->pdapi_aborted) { - out_flags |= MSG_TRUNC; - if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) - control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; - } - goto done_with_control; - } - if (so->so_rcv.sb_cc > held_length) { - control->held_length = so->so_rcv.sb_cc; - /* - * We don't use held_length while - * getting a message - */ - held_length = 0; - } - goto wait_some_more2; - } - goto get_more_data2; - } else { - /* hard way mbuf by mbuf */ - m = control->data; - if (control->end_added == 0) { - /* need the rlock */ - if (hold_rlock == 0) { - SCTP_INP_READ_LOCK(inp); - hold_rlock = 1; - } - } - if (control->spec_flags & M_NOTIFICATION) { - out_flags |= MSG_NOTIFICATION; + wakeup_read_socket = 0; + if ((control->end_added == 0) || + (TAILQ_NEXT(control, next) == NULL)) { + /* Need to get rlock */ + if (hold_rlock == 0) { + SCTP_INP_READ_LOCK(inp); + hold_rlock = 1; } - while ((m) && (cp_len > 0)) { - if (cp_len >= SCTP_BUF_LEN(m)) { - *mp = m; - atomic_subtract_int(&control->length, SCTP_BUF_LEN(m)); - if (uio) - uio->uio_resid -= SCTP_BUF_LEN(m); - cp_len -= SCTP_BUF_LEN(m); - control->data = SCTP_BUF_NEXT(m); - SCTP_BUF_NEXT(m) = NULL; -#ifdef SCTP_SB_LOGGING - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); -#endif - sctp_sbfree(control, stcb, &so->so_rcv, m); - freed_so_far += SCTP_BUF_LEN(m); -#ifdef SCTP_SB_LOGGING - sctp_sblog(&so->so_rcv, - control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); -#endif - mp = &SCTP_BUF_NEXT(m); - m = control->data; - } else { - /* - * got all he wants and its part of - * this mbuf only. - */ - if (uio) - uio->uio_resid -= SCTP_BUF_LEN(m); - cp_len -= SCTP_BUF_LEN(m); - if (hold_rlock) { - SCTP_INP_READ_UNLOCK(inp); - hold_rlock = 0; - } - if (hold_sblock) { - SOCKBUF_UNLOCK(&so->so_rcv); - hold_sblock = 0; - } - *mp = SCTP_M_COPYM(m, 0, cp_len, - M_TRYWAIT - ); -#ifdef SCTP_LOCK_LOGGING - sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCKBUF_R); -#endif - if (hold_sblock == 0) { - SOCKBUF_LOCK(&so->so_rcv); - hold_sblock = 1; - } - if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) - goto release; - - if (stcb && - stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { - no_rcv_needed = 1; - } - SCTP_BUF_RESV_UF(m, cp_len); - SCTP_BUF_LEN(m) -= cp_len; + } + if (control->end_added) { + out_flags |= MSG_EOR; + if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) + control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; + } + if (control->spec_flags & M_NOTIFICATION) { + out_flags |= MSG_NOTIFICATION; + } + uio->uio_resid = control->length; + *mp = control->data; + m = control->data; + while (m) { #ifdef SCTP_SB_LOGGING - sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len); + sctp_sblog(&so->so_rcv, + control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); #endif - freed_so_far += cp_len; - atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); - if (stcb) { - atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); - if ((freed_so_far >= rwnd_req) && - (control->do_not_ref_stcb == 0) && - (no_rcv_needed == 0)) - sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); - } + sctp_sbfree(control, stcb, &so->so_rcv, m); + freed_so_far += SCTP_BUF_LEN(m); #ifdef SCTP_SB_LOGGING - sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, - SCTP_LOG_SBRESULT, 0); + sctp_sblog(&so->so_rcv, + control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); #endif - goto release; - } - } + m = SCTP_BUF_NEXT(m); + } + control->data = control->tail_mbuf = NULL; + control->length = 0; + if (out_flags & MSG_EOR) { + /* Done with this control */ + goto done_with_control; } } release: @@ -5670,13 +5558,12 @@ sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) int -sctp_soreceive(so, psa, uio, mp0, controlp, flagsp) - struct socket *so; - struct sockaddr **psa; - struct uio *uio; - struct mbuf **mp0; - struct mbuf **controlp; - int *flagsp; +sctp_soreceive(struct socket *so, + struct sockaddr **psa, + struct uio *uio, + struct mbuf **mp0, + struct mbuf **controlp, + int *flagsp) { int error, fromlen; uint8_t sockbuf[256]; @@ -5725,3 +5612,155 @@ sctp_soreceive(so, psa, uio, mp0, controlp, flagsp) } return (error); } + + +int +sctp_l_soreceive(struct socket *so, + struct sockaddr **name, + struct uio *uio, + char **controlp, + int *controllen, + int *flag) +{ + int error, fromlen; + uint8_t sockbuf[256]; + struct sockaddr *from; + struct sctp_extrcvinfo sinfo; + int filling_sinfo = 1; + struct sctp_inpcb *inp; + + inp = (struct sctp_inpcb *)so->so_pcb; + /* pickup the assoc we are reading from */ + if (inp == NULL) { + return (EINVAL); + } + if ((sctp_is_feature_off(inp, + SCTP_PCB_FLAGS_RECVDATAIOEVNT)) || + (controlp == NULL)) { + /* user does not want the sndrcv ctl */ + filling_sinfo = 0; + } + if (name) { + from = (struct sockaddr *)sockbuf; + fromlen = sizeof(sockbuf); + from->sa_len = 0; + } else { + from = NULL; + fromlen = 0; + } + + error = sctp_sorecvmsg(so, uio, + (struct mbuf **)NULL, + from, fromlen, flag, + (struct sctp_sndrcvinfo *)&sinfo, + filling_sinfo); + if ((controlp) && (filling_sinfo)) { + /* + * copy back the sinfo in a CMSG format note that the caller + * has reponsibility for freeing the memory. + */ + if (filling_sinfo) + *controlp = sctp_build_ctl_cchunk(inp, + controllen, + (struct sctp_sndrcvinfo *)&sinfo); + } + if (name) { + /* copy back the address info */ + if (from && from->sa_len) { + *name = sodupsockaddr(from, M_WAIT); + } else { + *name = NULL; + } + } + return (error); +} + + + + + + + +int +sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, int totaddr, int *error) +{ + int added = 0; + int i; + struct sctp_inpcb *inp; + struct sockaddr *sa; + size_t incr = 0; + + sa = addr; + inp = stcb->sctp_ep; + *error = 0; + for (i = 0; i < totaddr; i++) { + if (sa->sa_family == AF_INET) { + incr = sizeof(struct sockaddr_in); + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + /* assoc gone no un-lock */ + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); + *error = ENOBUFS; + goto out_now; + } + added++; + } else if (sa->sa_family == AF_INET6) { + incr = sizeof(struct sockaddr_in6); + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + /* assoc gone no un-lock */ + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); + *error = ENOBUFS; + goto out_now; + } + added++; + } + sa = (struct sockaddr *)((caddr_t)sa + incr); + } +out_now: + return (added); +} + +struct sctp_tcb * +sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, int *totaddr, + int *num_v4, int *num_v6, int *error, int max) +{ + struct sockaddr *sa; + struct sctp_tcb *stcb = NULL; + size_t incr, at, i; + + at = incr = 0; + sa = addr; + *error = *num_v6 = *num_v4 = 0; + /* account and validate addresses */ + for (i = 0; i < *totaddr; i++) { + if (sa->sa_family == AF_INET) { + (*num_v4) += 1; + incr = sizeof(struct sockaddr_in); + } else if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)sa; + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + /* Must be non-mapped for connectx */ + *error = EINVAL; + return (NULL); + } + (*num_v6) += 1; + incr = sizeof(struct sockaddr_in6); + } else { + *totaddr = i; + /* we are done */ + break; + } + stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); + if (stcb != NULL) { + /* Already have or am bring up an association */ + return (stcb); + } + if ((at + incr) > max) { + *totaddr = i; + break; + } + sa = (struct sockaddr *)((caddr_t)sa + incr); + } + return ((struct sctp_tcb *)NULL); +} |