1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2012 David Hoeppner.  All rights reserved.
  29  */
  30 
  31 /*
  32  * This file contains function related to binding.
  33  */
  34 
  35 #include <sys/types.h>
  36 #include <sys/stream.h>
  37 #include <sys/strsun.h>
  38 #include <sys/strsubr.h>
  39 #include <sys/stropts.h>
  40 #include <sys/strlog.h>
  41 #define _SUN_TPI_VERSION 2
  42 #include <sys/tihdr.h>
  43 #include <sys/suntpi.h>
  44 #include <sys/xti_inet.h>
  45 #include <sys/squeue_impl.h>
  46 #include <sys/squeue.h>
  47 #include <sys/tsol/tnet.h>
  48 
  49 #include <rpc/pmap_prot.h>
  50 
  51 #include <inet/common.h>
  52 #include <inet/dccp_impl.h>
  53 #include <inet/ip.h>
  54 #include <inet/proto_set.h>
  55 
  56 #include <sys/cmn_err.h>
  57 
  58 /* Setable in /etc/system */
  59 static uint32_t dccp_random_anon_port = 1;
  60 
  61 static int      dccp_bind_select_lport(dccp_t *, in_port_t *, boolean_t,
  62                     cred_t *);
  63 static in_port_t dccp_get_next_priv_port(const dccp_t *);
  64 
  65 void
  66 dccp_bind_hash_insert(dccp_df_t *tbf, dccp_t *dccp, int caller_holds_lock)
  67 {
  68         conn_t  *connp = dccp->dccp_connp;
  69         conn_t  *connext;
  70         dccp_t  **dccpp;
  71         dccp_t  *dccpnext;
  72         dccp_t  *dccphash;
  73 
  74         cmn_err(CE_NOTE, "dccp_bind.c: dccp_bind_hash_insert");
  75 
  76         /* XXX:DCCP */
  77 
  78         dccpp = &tbf->df_dccp;
  79         if (!caller_holds_lock) {
  80                 mutex_enter(&tbf->df_lock);
  81         } else {
  82                 ASSERT(MUTEX_HELD(&tbf->df_lock));
  83         }
  84 
  85         dccphash = dccpp[0];
  86         dccpnext = NULL;
  87 
  88         if (dccphash != NULL) {
  89                 /* Look for an entry using the same port */
  90                 while ((dccphash = dccpp[0]) != NULL &&
  91                     connp->conn_lport != dccphash->dccp_connp->conn_lport) {
  92                         dccpp = &(dccphash->dccp_bind_hash);
  93                 }
  94 
  95                 /* The port was not found, just add to the end */
  96                 if (dccphash == NULL) {
  97                         goto insert;
  98                 }
  99 
 100                 dccpnext = dccphash;
 101                 connext = dccpnext->dccp_connp;
 102                 dccphash = NULL;
 103                 if (V6_OR_V4_INADDR_ANY(connp->conn_bound_addr_v6) &&
 104                     !V6_OR_V4_INADDR_ANY(connext->conn_bound_addr_v6)) {
 105                         while ((dccpnext = dccpp[0]) != NULL) {
 106                                 connext = dccpnext->dccp_connp;
 107                                 if (!V6_OR_V4_INADDR_ANY(
 108                                     connext->conn_bound_addr_v6)) {
 109                                         dccpp = &(dccpnext->dccp_bind_hash_port);
 110                                 } else {
 111                                         break;
 112                                 }
 113                         }
 114 
 115                         if (dccpnext != NULL) {
 116                                 dccpnext->dccp_ptpbhn = &dccp->dccp_bind_hash_port;
 117                                 dccphash = dccpnext->dccp_bind_hash;
 118                                 if (dccphash != NULL) {
 119                                         dccphash->dccp_ptpbhn =
 120                                             &(dccp->dccp_bind_hash);
 121                                         dccpnext->dccp_bind_hash = NULL;
 122                                 }
 123                         }
 124                 } else {
 125                         dccpnext->dccp_ptpbhn = &dccp->dccp_bind_hash_port;
 126                         dccphash = dccpnext->dccp_bind_hash;
 127                         if (dccphash != NULL) {
 128                                 dccphash->dccp_ptpbhn =
 129                                     &(dccp->dccp_bind_hash);
 130                                 dccpnext->dccp_bind_hash = NULL;
 131                         }
 132                 }
 133         }
 134 
 135 insert:
 136         dccp->dccp_bind_hash_port = dccpnext;
 137         dccp->dccp_bind_hash = dccphash;
 138         dccp->dccp_ptpbhn = dccpp;
 139         dccpp[0] = dccp;
 140 
 141         if (!caller_holds_lock) {
 142                 mutex_exit(&tbf->df_lock);
 143         }
 144 }
 145 
 146 /*
 147  * Remove bind hash.
 148  */
 149 void
 150 dccp_bind_hash_remove(dccp_t *dccp)
 151 {
 152         conn_t          *connp = dccp->dccp_connp;
 153         dccp_t          *dccpnext;
 154         dccp_stack_t    *dccps = dccp->dccp_dccps;
 155         kmutex_t        *lockp;
 156 
 157         cmn_err(CE_NOTE, "dccp_bind.c: dccp_bind_hash_remove");
 158 
 159         /* Nothing to remove */
 160         if (dccp->dccp_ptpbhn == NULL) {
 161                 return;
 162         }
 163 
 164         ASSERT(connp->conn_lport != 0);
 165         lockp = &dccps->dccps_bind_fanout[DCCP_BIND_HASH(connp->conn_lport,
 166             dccps->dccps_bind_fanout_size)].df_lock;
 167         ASSERT(lockp != NULL);
 168 
 169         mutex_enter(lockp);
 170         if (dccp->dccp_ptpbhn) {
 171                 dccpnext = dccp->dccp_bind_hash_port;
 172                 if (dccpnext != NULL) {
 173                         dccp->dccp_bind_hash_port = NULL;
 174                         dccpnext->dccp_ptpbhn = dccp->dccp_ptpbhn;
 175                         dccpnext->dccp_bind_hash = dccp->dccp_bind_hash;
 176                         if (dccpnext->dccp_bind_hash != NULL) {
 177                                 dccpnext->dccp_bind_hash->dccp_ptpbhn =
 178                                     &(dccpnext->dccp_bind_hash);
 179                                 dccp->dccp_bind_hash = NULL;
 180                         }
 181                 } else if ((dccpnext = dccp->dccp_bind_hash) != NULL) {
 182                         dccpnext->dccp_ptpbhn = dccp->dccp_ptpbhn;
 183                         dccp->dccp_bind_hash = NULL;
 184                 }
 185                 *dccp->dccp_ptpbhn = dccpnext;
 186                 dccp->dccp_ptpbhn = NULL;
 187         }
 188         mutex_exit(lockp);
 189 }
 190 
 191 /*
 192  * Check for a valid address and get a local port.
 193  */
 194 int
 195 dccp_bind_check(conn_t *connp, struct sockaddr *sa, socklen_t len, cred_t *cr,
 196     boolean_t bind_to_req_port_only)
 197 {
 198         dccp_t          *dccp = connp->conn_dccp;
 199         ip_stack_t      *ips = connp->conn_netstack->netstack_ip;
 200         ip_xmit_attr_t  *ixa = connp->conn_ixa;
 201         sin_t           *sin;
 202         sin6_t          *sin6;
 203         ipaddr_t        v4addr;
 204         in6_addr_t      v6addr;
 205         ip_laddr_t      laddr_type = IPVL_UNICAST_UP;
 206         zoneid_t        zoneid = IPCL_ZONEID(connp);
 207         in_port_t       requested_port;
 208         uint_t          scopeid = 0;
 209         int             error;
 210 
 211         cmn_err(CE_NOTE, "dccp_bind.c: dccp_bind_check");
 212 
 213         ASSERT((uintptr_t)len <= (uintptr_t)INT_MAX);
 214 
 215         /*
 216          * We should be in a pre-listen state.
 217          */
 218         if (dccp->dccp_state == DCCPS_LISTEN) {
 219                 return (0);
 220         } else if (dccp->dccp_state > DCCPS_LISTEN) {
 221                 if (connp->conn_debug) {
 222                         (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
 223                             "dccp_bind: bad state, %d", dccp->dccp_state);
 224                 }
 225                 return (-TOUTSTATE);
 226         }
 227 
 228         /*
 229          * Check for a valid address parameter. Then validate the
 230          * addresses and copy them and the required port in.
 231          */
 232         ASSERT(sa != NULL && len != 0);
 233 
 234         if (!OK_32PTR((char *)sa)) {
 235                 if (connp->conn_debug) {
 236                         (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
 237                             "dccp_bind: bad address parameter, "
 238                             "address %p, len %d", (void *)sa, len);
 239                 }
 240                 return (-TPROTO);
 241         }
 242 
 243         error = proto_verify_ip_addr(connp->conn_family, sa, len);
 244         if (error != 0) {
 245                 return (error);
 246         }
 247 
 248         switch (len) {
 249         case sizeof (sin_t):
 250                 sin = (sin_t *)sa;
 251                 v4addr = sin->sin_addr.s_addr;
 252                 requested_port = ntohs(sin->sin_port);
 253                 IN6_IPADDR_TO_V4MAPPED(v4addr, &v6addr);
 254                 if (v4addr != INADDR_ANY) {
 255                         laddr_type = ip_laddr_verify_v4(v4addr, zoneid, ips,
 256                             B_FALSE);
 257                 }
 258                 break;
 259 
 260         case sizeof (sin6_t):
 261                 sin6 = (sin6_t *)sa;
 262                 v6addr = sin6->sin6_addr;
 263                 requested_port = ntohs(sin6->sin6_port);
 264                 if (IN6_IS_ADDR_V4MAPPED(&v6addr)) {
 265                         if (connp->conn_ipv6_v6only) {
 266                                 return (EADDRNOTAVAIL);
 267                         }
 268 
 269                         IN6_V4MAPPED_TO_IPADDR(&v6addr, v4addr);
 270                         if (v4addr != INADDR_ANY) {
 271                                 laddr_type = ip_laddr_verify_v4(v4addr, zoneid,
 272                                     ips, B_FALSE);
 273                         }
 274                 } else {
 275                         if (!IN6_IS_ADDR_UNSPECIFIED(&v6addr)) {
 276                                 if (IN6_IS_ADDR_LINKSCOPE(&v6addr)) {
 277                                         scopeid = sin6->sin6_scope_id;
 278                                         laddr_type = ip_laddr_verify_v6(&v6addr,
 279                                             zoneid, ips, B_FALSE, scopeid);
 280                                 }
 281                         }
 282                 }
 283                 break;
 284 
 285         default:
 286                 if (connp->conn_debug) {
 287                         (void) strlog(DCCP_MOD_ID, 0, 1, SL_ERROR|SL_TRACE,
 288                             "dccp_bind: bad address length, %d", len);
 289                 }
 290                 return (EAFNOSUPPORT);
 291         }
 292 
 293         if (laddr_type == IPVL_BAD) {
 294                 return (EADDRNOTAVAIL);
 295         }
 296 
 297         connp->conn_bound_addr_v6 = v6addr;
 298         if (scopeid != 0) {
 299                 ixa->ixa_flags |= IXAF_SCOPEID_SET;
 300                 ixa->ixa_scopeid = scopeid;
 301                 connp->conn_incoming_ifindex = scopeid;
 302         } else {
 303                 ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
 304                 connp->conn_incoming_ifindex = connp->conn_bound_if;
 305         }
 306 
 307         connp->conn_laddr_v6 = v6addr;
 308         connp->conn_saddr_v6 = v6addr;
 309 
 310         bind_to_req_port_only = requested_port != 0 && bind_to_req_port_only;
 311 
 312         error = dccp_bind_select_lport(dccp, &requested_port,
 313             bind_to_req_port_only, cr);
 314         if (error != 0) {
 315                 connp->conn_laddr_v6 = ipv6_all_zeros;
 316                 connp->conn_saddr_v6 = ipv6_all_zeros;
 317                 connp->conn_bound_addr_v6 = ipv6_all_zeros;
 318         }
 319 
 320         return (error);
 321 }
 322 
 323 /*
 324  * Bind to a local port.
 325  */
 326 static int
 327 dccp_bind_select_lport(dccp_t *dccp, in_port_t *requested_port_ptr,
 328     boolean_t bind_to_req_port_only, cred_t *cr)
 329 {
 330         dccp_stack_t    *dccps = dccp->dccp_dccps;
 331         conn_t          *connp = dccp->dccp_connp;
 332         zone_t          *zone;
 333         in_port_t       allocated_port;
 334         in_port_t       requested_port = *requested_port_ptr;
 335         in_port_t       mlp_port;
 336         in6_addr_t      v6addr = connp->conn_laddr_v6;
 337         mlp_type_t      addrtype;
 338         mlp_type_t      mlptype;
 339         boolean_t       user_specified;
 340 
 341         cmn_err(CE_NOTE, "dccp_bind.c: dccp_bind_select_lport");
 342 
 343         ASSERT(cr != NULL);
 344 
 345         mlptype = mlptSingle;
 346         mlp_port = requested_port;
 347         if (requested_port == 0) {
 348                 requested_port = connp->conn_anon_priv_bind ?
 349                     dccp_get_next_priv_port(dccp) :
 350                     dccp_update_next_port(dccps->dccps_next_port_to_try,
 351                     dccp, B_TRUE);
 352                 if (requested_port == 0) {
 353                         return (-TNOADDR);
 354                 }
 355                 user_specified = B_FALSE;
 356 
 357                 if (connp->conn_anon_mlp && is_system_labeled()) {
 358                         zone = crgetzone(cr);
 359                         addrtype = tsol_mlp_addr_type(
 360                             connp->conn_allzones ? ALL_ZONES : zone->zone_id,
 361                             IPV6_VERSION, &v6addr,
 362                             dccps->dccps_netstack->netstack_ip);
 363                         if (addrtype == mlptSingle) {
 364                                 return (-TNOADDR);
 365                         }
 366                         mlptype = tsol_mlp_port_type(zone, IPPROTO_DCCP,
 367                             PMAPPORT, addrtype);
 368                         mlp_port = PMAPPORT;
 369                 }
 370         }  else {
 371                 int             i;
 372                 boolean_t       priv = B_FALSE;
 373 
 374                 if (requested_port < dccps->dccps_smallest_nonpriv_port) {
 375                         priv = B_TRUE;
 376                 } else {
 377                         for (i = 0; i < dccps->dccps_num_epriv_ports; i++) {
 378                                 if (requested_port ==
 379                                     dccps->dccps_epriv_ports[i]) {
 380                                         priv = B_TRUE;
 381                                         break;
 382                                 }
 383                         }
 384                 }
 385 
 386                 if (priv) {
 387                         if (secpolicy_net_privaddr(cr, requested_port,
 388                             IPPROTO_DCCP) != 0) {
 389                                 if (connp->conn_debug) {
 390                                         (void) strlog(DCCP_MOD_ID, 0, 1,
 391                                             SL_ERROR|SL_TRACE,
 392                                             "tcp_bind: no priv for port %d",
 393                                             requested_port);
 394                                 }
 395                                 return (-TACCES);
 396                         }
 397                 }
 398 
 399                 user_specified = B_TRUE;
 400 
 401                 connp = dccp->dccp_connp;
 402                 if (is_system_labeled()) {
 403                         zone = crgetzone(cr);
 404                         addrtype = tsol_mlp_addr_type(
 405                             connp->conn_allzones ? ALL_ZONES : zone->zone_id,
 406                             IPV6_VERSION, &v6addr,
 407                             dccps->dccps_netstack->netstack_ip);
 408                         if (addrtype == mlptSingle) {
 409                                 return (-TNOADDR);
 410                         }
 411                         mlptype = tsol_mlp_port_type(zone, IPPROTO_DCCP,
 412                             requested_port, addrtype);
 413                 }
 414         }
 415 
 416         if (mlptype != mlptSingle) {
 417                 if (secpolicy_net_bindmlp(cr) != 0) {
 418                         if (connp->conn_debug) {
 419                                 (void) strlog(DCCP_MOD_ID, 0, 1,
 420                                     SL_ERROR|SL_TRACE,
 421                                     "dccp_bind: no priv for multilevel port %d",
 422                                     requested_port);
 423                         }
 424                         return (-TACCES);
 425                 }
 426 
 427                 /*
 428                  * If we're specifically binding a shared IP address and the
 429                  * port is MLP on shared addresses, then check to see if this
 430                  * zone actually owns the MLP.  Reject if not.
 431                  */
 432                 if (mlptype == mlptShared && addrtype == mlptShared) {
 433                         /*
 434                          * No need to handle exclusive-stack zones since
 435                          * ALL_ZONES only applies to the shared stack.
 436                          */
 437                         zoneid_t        mlpzone;
 438 
 439                         mlpzone = tsol_mlp_findzone(IPPROTO_DCCP,
 440                             htons(mlp_port));
 441                         if (connp->conn_zoneid != mlpzone) {
 442                                 if (connp->conn_debug) {
 443                                         (void) strlog(DCCP_MOD_ID, 0, 1,
 444                                             SL_ERROR|SL_TRACE,
 445                                             "dccp_bind: attempt to bind port "
 446                                             "%d on shared addr in zone %d "
 447                                             "(should be %d)",
 448                                             mlp_port, connp->conn_zoneid,
 449                                             mlpzone);
 450                                 }
 451                                 return (-TACCES);
 452                         }
 453                 }
 454 
 455                 if (!user_specified) {
 456                         int     error;
 457 
 458                         error = tsol_mlp_anon(zone, mlptype, connp->conn_proto,
 459                             requested_port, B_TRUE);
 460                         if (error != 0) {
 461                                 if (connp->conn_debug) {
 462                                         (void) strlog(DCCP_MOD_ID, 0, 1,
 463                                             SL_ERROR|SL_TRACE,
 464                                             "dccp_bind: cannot establish anon "
 465                                             "MLP for port %d",
 466                                             requested_port);
 467                                 }
 468                                 return (error);
 469                         }
 470                         connp->conn_anon_port = B_TRUE;
 471                 }
 472                 connp->conn_mlp_type = mlptype;
 473         }
 474 
 475         allocated_port = dccp_bindi(dccp, requested_port, &v6addr,
 476             connp->conn_reuseaddr, B_FALSE, bind_to_req_port_only,
 477             user_specified);
 478 
 479         if (allocated_port == 0) {
 480                 connp->conn_mlp_type = mlptSingle;
 481 
 482                 if (connp->conn_anon_port) {
 483                         connp->conn_anon_port = B_FALSE;
 484                         (void) tsol_mlp_anon(zone, mlptype, connp->conn_proto,
 485                             requested_port, B_FALSE);
 486                 }
 487 
 488                 if (bind_to_req_port_only) {
 489                         if (connp->conn_debug) {
 490                                 (void) strlog(DCCP_MOD_ID, 0, 1,
 491                                     SL_ERROR|SL_TRACE,
 492                                     "dccp_bind: requested addr busy");
 493                         }
 494                         return (-TADDRBUSY);
 495                 } else {
 496                         /* If we are out of ports, fail the bind */
 497                         if (connp->conn_debug) {
 498                                 (void) strlog(DCCP_MOD_ID, 0, 1,
 499                                     SL_ERROR|SL_TRACE,
 500                                     "dccp_bind: out of ports?");
 501                         }
 502                         return (-TNOADDR);
 503                 }
 504         }
 505 
 506         /* Pass the allocated port back */
 507         *requested_port_ptr = allocated_port;
 508         return (0);
 509 }
 510 
 511 in_port_t
 512 dccp_bindi(dccp_t *dccp, in_port_t port, const in6_addr_t *laddr,
 513     int reuseaddr, boolean_t quick_connect, boolean_t bind_to_req_port_only,
 514     boolean_t user_specified)
 515 {
 516         dccp_stack_t    *dccps = dccp->dccp_dccps;
 517         conn_t          *connp = dccp->dccp_connp;
 518         int             count = 0;
 519         int             loopmax;
 520 
 521         cmn_err(CE_NOTE, "dccp_bind.c: dccp_bindi");
 522 
 523         if (bind_to_req_port_only) {
 524                 loopmax = 1;
 525         } else {
 526                 if (connp->conn_anon_priv_bind) {
 527                         loopmax = IPPORT_RESERVED -
 528                             dccps->dccps_min_anonpriv_port;
 529                 } else {
 530                         loopmax = (dccps->dccps_largest_anon_port -
 531                             dccps->dccps_smallest_anon_port + 1);
 532                 }
 533         }
 534 
 535         do {
 536                 conn_t          *lconnp;
 537                 dccp_t          *ldccp;
 538                 dccp_df_t       *ldf;
 539                 uint16_t        lport;
 540 
 541                 lport = htons(port);
 542 
 543                 dccp_bind_hash_remove(dccp);
 544                 ldf = &dccps->dccps_bind_fanout[DCCP_BIND_HASH(lport,
 545                     dccps->dccps_bind_fanout_size)];
 546                 mutex_enter(&ldf->df_lock);
 547                 for (ldccp = ldf->df_dccp; ldccp != NULL;
 548                     ldccp = ldccp->dccp_bind_hash) {
 549                         if (lport == ldccp->dccp_connp->conn_lport) {
 550                                 break;
 551                         }
 552                 }
 553 
 554                 if (ldccp != NULL) {
 555                         /* The port number is busy */
 556                         mutex_exit(&ldf->df_lock);
 557                 } else {
 558                         /*
 559                          * This port is ours. Insert in fanout and mark as
 560                          * bound to prevent others from getting the port
 561                          * number.
 562                          */
 563                         dccp->dccp_state = DCCPS_BOUND;
 564                         DTRACE_DCCP6(state__change, void, NULL,
 565                             ip_xmit_attr_t *, connp->conn_ixa,
 566                             void, NULL, dccp_t *, dccp, void, NULL,
 567                             int32_t, DCCPS_CLOSED);
 568 
 569                         connp->conn_lport = htons(port);
 570 
 571                         ASSERT(&dccps->dccps_bind_fanout[DCCP_BIND_HASH(
 572                              connp->conn_lport,
 573                              dccps->dccps_bind_fanout_size)] == ldf);
 574                         dccp_bind_hash_insert(ldf, dccp, 1);
 575 
 576                         mutex_exit(&ldf->df_lock);
 577 
 578                         /*
 579                          * We don't want tcp_next_port_to_try to "inherit"
 580                          * a port number supplied by the user in a bind.
 581                          */
 582                         if (user_specified) {
 583                                 return (port);
 584                         }
 585 
 586                         /*
 587                          * This is the only place where dccp_next_port_to_try
 588                          * is updated. After the update, it may or may not
 589                          * be in the valid range.
 590                          */
 591                         if (!connp->conn_anon_priv_bind) {
 592                                 dccps->dccps_next_port_to_try = port + 1;
 593                         }
 594 
 595                         return (port);
 596                 }
 597 
 598                 if (connp->conn_anon_priv_bind) {
 599                         port = dccp_get_next_priv_port(dccp);
 600                 } else {
 601                         if (count == 0 && user_specified) {
 602                                 /*
 603                                  * We may have to return an anonymous port. So
 604                                  * get one to start with.
 605                                  */
 606                                 port =
 607                                     dccp_update_next_port(
 608                                     dccps->dccps_next_port_to_try,
 609                                     dccp, B_TRUE);
 610                                 user_specified = B_FALSE;
 611                         } else {
 612                                 port = dccp_update_next_port(port + 1, dccp,
 613                                     B_FALSE);
 614                         }
 615                 }
 616 
 617                 if (port == 0) {
 618                         break;
 619                 }
 620 
 621         } while (++count < loopmax);
 622 
 623         cmn_err(CE_NOTE, "dccp_bind.c: dccp_bindi exit");
 624 
 625         return (0);
 626 }
 627 
 628 in_port_t
 629 dccp_update_next_port(in_port_t port, const dccp_t *dccp, boolean_t random)
 630 {
 631         dccp_stack_t    *dccps = dccp->dccp_dccps;
 632         boolean_t       restart = B_FALSE;
 633         int             i;
 634 
 635         cmn_err(CE_NOTE, "dccp_bind.c: dccp_update_next_port");
 636 
 637         if (random && dccp_random_anon_port != 0) {
 638                 (void) random_get_pseudo_bytes((uint8_t *)&port,
 639                     sizeof (in_port_t));
 640 
 641                 if (port < dccps->dccps_smallest_anon_port) {
 642                         port = dccps->dccps_smallest_anon_port +
 643                             port % (dccps->dccps_largest_anon_port -
 644                             dccps->dccps_smallest_anon_port);
 645                 }
 646         }
 647 
 648 retry:
 649         if (port < dccps->dccps_smallest_anon_port) {
 650                 port = (in_port_t)dccps->dccps_smallest_anon_port;
 651         }
 652 
 653         if (port > dccps->dccps_largest_anon_port) {
 654                 if (restart) {
 655                         return (0);
 656                 }
 657                 restart = B_TRUE;
 658                 port = (in_port_t)dccps->dccps_smallest_anon_port;
 659         }
 660 
 661         if (port < dccps->dccps_smallest_nonpriv_port) {
 662                 port = (in_port_t)dccps->dccps_smallest_nonpriv_port;
 663         }
 664 
 665         for (i = 0; i < dccps->dccps_num_epriv_ports; i++) {
 666                 if (port == dccps->dccps_epriv_ports[i]) {
 667                         port++;
 668                         goto retry;
 669                 }
 670         }
 671 
 672         return (port);
 673 }
 674 
 675 /*
 676  * Return the next anonymous port in the privileged port range for
 677  * bind checking.  It starts at IPPORT_RESERVED - 1 and goes
 678  * downwards.  This is the same behavior as documented in the userland
 679  * library call rresvport(3N).
 680  *
 681  * TS note: skip multilevel ports.
 682  */
 683 static in_port_t
 684 dccp_get_next_priv_port(const dccp_t *dccp)
 685 {
 686         static in_port_t next_priv_port = IPPORT_RESERVED - 1;
 687         dccp_stack_t    *dccps = dccp->dccp_dccps;
 688         in_port_t       nextport;
 689         boolean_t       restart = B_FALSE;
 690 
 691 retry:
 692         if (next_priv_port < dccps->dccps_min_anonpriv_port ||
 693             next_priv_port >= IPPORT_RESERVED) {
 694                 next_priv_port = IPPORT_RESERVED - 1;
 695                 if (restart) {
 696                         return (0);
 697                 }
 698                 restart = B_TRUE;
 699         }
 700 
 701         if (is_system_labeled() &&
 702             (nextport = tsol_next_port(crgetzone(dccp->dccp_connp->conn_cred),
 703             next_priv_port, IPPROTO_DCCP, B_FALSE)) != 0) {
 704                 next_priv_port = nextport;
 705                 goto retry;
 706         }
 707 
 708         return (next_priv_port--);
 709 }