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 }