/* * Perform bind/unbind operation of a list of addresses on a sctp_t */ int sctp_bindx(sctp_t *sctp, const void *addrs, int addrcnt, int bindop) { ASSERT(sctp != NULL); ASSERT(addrs != NULL); ASSERT(addrcnt > 0); switch (bindop) { case SCTP_BINDX_ADD_ADDR: return (sctp_bind_add(sctp, addrs, addrcnt, B_FALSE, sctp->sctp_lport)); case SCTP_BINDX_REM_ADDR: return (sctp_bind_del(sctp, addrs, addrcnt, B_FALSE)); default: return (EINVAL); } }
/* * Bind the sctp_t to a sockaddr, which includes an address and other * information, such as port or flowinfo. */ int sctp_bind(sctp_t *sctp, struct sockaddr *sa, socklen_t len) { int user_specified; boolean_t bind_to_req_port_only; in_port_t requested_port; in_port_t allocated_port; int err = 0; ASSERT(sctp != NULL); ASSERT(sa); RUN_SCTP(sctp); if (sctp->sctp_state > SCTPS_BOUND) { err = EINVAL; goto done; } switch (sa->sa_family) { case AF_INET: if (len < sizeof (struct sockaddr_in) || sctp->sctp_family == AF_INET6) { err = EINVAL; goto done; } requested_port = ntohs(((struct sockaddr_in *)sa)->sin_port); break; case AF_INET6: if (len < sizeof (struct sockaddr_in6) || sctp->sctp_family == AF_INET) { err = EINVAL; goto done; } requested_port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); /* Set the flowinfo. */ sctp->sctp_ip6h->ip6_vcf = (IPV6_DEFAULT_VERS_AND_FLOW & IPV6_VERS_AND_FLOW_MASK) | (((struct sockaddr_in6 *)sa)->sin6_flowinfo & ~IPV6_VERS_AND_FLOW_MASK); break; default: err = EAFNOSUPPORT; goto done; } bind_to_req_port_only = requested_port == 0 ? B_FALSE : B_TRUE; err = sctp_select_port(sctp, &requested_port, &user_specified); if (err != 0) goto done; if ((err = sctp_bind_add(sctp, sa, 1, B_TRUE, user_specified == 1 ? htons(requested_port) : 0)) != 0) { goto done; } err = sctp_bindi(sctp, requested_port, bind_to_req_port_only, user_specified, &allocated_port); if (err != 0) { sctp_free_saddrs(sctp); } else { ASSERT(sctp->sctp_state == SCTPS_BOUND); } done: WAKE_SCTP(sctp); return (err); }
/* * Bind the sctp_t to a sockaddr, which includes an address and other * information, such as port or flowinfo. */ int sctp_bind(sctp_t *sctp, struct sockaddr *sa, socklen_t len) { int user_specified; boolean_t bind_to_req_port_only; in_port_t requested_port; in_port_t allocated_port; int err = 0; conn_t *connp = sctp->sctp_connp; uint_t scope_id; sin_t *sin; sin6_t *sin6; ASSERT(sctp != NULL); RUN_SCTP(sctp); if ((sctp->sctp_state >= SCTPS_BOUND) || (sctp->sctp_connp->conn_state_flags & CONN_CLOSING) || (sa == NULL || len == 0)) { /* * Multiple binds not allowed for any SCTP socket * Also binding with null address is not supported. */ err = EINVAL; goto done; } switch (sa->sa_family) { case AF_INET: sin = (sin_t *)sa; if (len < sizeof (struct sockaddr_in) || connp->conn_family == AF_INET6) { err = EINVAL; goto done; } requested_port = ntohs(sin->sin_port); break; case AF_INET6: sin6 = (sin6_t *)sa; if (len < sizeof (struct sockaddr_in6) || connp->conn_family == AF_INET) { err = EINVAL; goto done; } requested_port = ntohs(sin6->sin6_port); /* Set the flowinfo. */ connp->conn_flowinfo = sin6->sin6_flowinfo & ~IPV6_VERS_AND_FLOW_MASK; scope_id = sin6->sin6_scope_id; if (scope_id != 0 && IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr)) { connp->conn_ixa->ixa_flags |= IXAF_SCOPEID_SET; connp->conn_ixa->ixa_scopeid = scope_id; connp->conn_incoming_ifindex = scope_id; } else { connp->conn_ixa->ixa_flags &= ~IXAF_SCOPEID_SET; connp->conn_incoming_ifindex = connp->conn_bound_if; } break; default: err = EAFNOSUPPORT; goto done; } bind_to_req_port_only = requested_port == 0 ? B_FALSE : B_TRUE; err = sctp_select_port(sctp, &requested_port, &user_specified); if (err != 0) goto done; if ((err = sctp_bind_add(sctp, sa, 1, B_TRUE, user_specified == 1 ? htons(requested_port) : 0)) != 0) { goto done; } err = sctp_bindi(sctp, requested_port, bind_to_req_port_only, user_specified, &allocated_port); if (err != 0) { sctp_free_saddrs(sctp); } else { ASSERT(sctp->sctp_state == SCTPS_BOUND); } done: WAKE_SCTP(sctp); return (err); }