@@ -106,6 +106,9 @@ __FBSDID("$FreeBSD$");
106106
107107#ifdef FSTACK
108108#include "ff_host_interface.h"
109+
110+ int ff_in_pcb_lport (struct inpcb * inp , struct in_addr * laddrp , u_short * lportp ,
111+ struct in_addr * faddrp , u_short * fportp , struct ucred * cred , int lookupflags );
109112#endif
110113
111114static struct callout ipport_tick_callout ;
@@ -500,6 +503,192 @@ in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp,
500503 return (0 );
501504}
502505
506+ #ifdef FSTACK
507+ int
508+ ff_in_pcb_lport (struct inpcb * inp , struct in_addr * laddrp , u_short * lportp ,
509+ struct in_addr * faddrp , u_short * fportp , struct ucred * cred , int lookupflags )
510+ {
511+ struct inpcbinfo * pcbinfo ;
512+ struct inpcb * tmpinp ;
513+ unsigned short * lastport ;
514+ int count , dorandom , error ;
515+ u_short aux , first , last , lport ;
516+ #ifdef INET
517+ struct in_addr laddr , faddr ;
518+ #endif
519+ u_short rss_first , rss_last , * rss_portrange ;
520+ /* 0:not init, 1:init successed, -1:init failed */
521+ static int rss_tbl_init = 0 ;
522+ int rss_ret , rss_port_idx , rss_match = 0 ;
523+ struct ifaddr * ifa ;
524+ struct ifnet * ifp ;
525+
526+ pcbinfo = inp -> inp_pcbinfo ;
527+
528+ /*
529+ * Because no actual state changes occur here, a global write lock on
530+ * the pcbinfo isn't required.
531+ */
532+ INP_LOCK_ASSERT (inp );
533+ INP_HASH_LOCK_ASSERT (pcbinfo );
534+
535+ if (inp -> inp_flags & INP_HIGHPORT ) {
536+ first = V_ipport_hifirstauto ; /* sysctl */
537+ last = V_ipport_hilastauto ;
538+ lastport = & pcbinfo -> ipi_lasthi ;
539+ } else if (inp -> inp_flags & INP_LOWPORT ) {
540+ error = priv_check_cred (cred , PRIV_NETINET_RESERVEDPORT , 0 );
541+ if (error )
542+ return (error );
543+ first = V_ipport_lowfirstauto ; /* 1023 */
544+ last = V_ipport_lowlastauto ; /* 600 */
545+ lastport = & pcbinfo -> ipi_lastlow ;
546+ } else {
547+ first = V_ipport_firstauto ; /* sysctl */
548+ last = V_ipport_lastauto ;
549+ lastport = & pcbinfo -> ipi_lastport ;
550+ }
551+ /*
552+ * For UDP(-Lite), use random port allocation as long as the user
553+ * allows it. For TCP (and as of yet unknown) connections,
554+ * use random port allocation only if the user allows it AND
555+ * ipport_tick() allows it.
556+ */
557+ if (V_ipport_randomized &&
558+ (!V_ipport_stoprandom || pcbinfo == & V_udbinfo ||
559+ pcbinfo == & V_ulitecbinfo ))
560+ dorandom = 1 ;
561+ else
562+ dorandom = 0 ;
563+ /*
564+ * It makes no sense to do random port allocation if
565+ * we have the only port available.
566+ */
567+ if (first == last )
568+ dorandom = 0 ;
569+ /* Make sure to not include UDP(-Lite) packets in the count. */
570+ if (pcbinfo != & V_udbinfo || pcbinfo != & V_ulitecbinfo )
571+ V_ipport_tcpallocs ++ ;
572+ /*
573+ * Instead of having two loops further down counting up or down
574+ * make sure that first is always <= last and go with only one
575+ * code path implementing all logic.
576+ */
577+ if (first > last ) {
578+ aux = first ;
579+ first = last ;
580+ last = aux ;
581+ }
582+
583+ #ifdef INET
584+ /* Make the compiler happy. */
585+ laddr .s_addr = 0 ;
586+ if ((inp -> inp_vflag & (INP_IPV4 |INP_IPV6 )) == INP_IPV4 ) {
587+ KASSERT (laddrp != NULL , ("%s: laddrp NULL for v4 inp %p" ,
588+ __func__ , inp ));
589+ laddr = * laddrp ;
590+ faddr = * faddrp ;
591+ }
592+ #endif
593+ tmpinp = NULL ; /* Make compiler happy. */
594+ lport = * lportp ;
595+
596+ if (rss_tbl_init == 0 ) {
597+ rss_ret = ff_rss_tbl_set_portrange (first , last );
598+ if (rss_ret < 0 )
599+ rss_tbl_init = -1 ;
600+ else
601+ rss_tbl_init = 1 ;
602+ }
603+
604+ if (rss_tbl_init == 1 ) {
605+ rss_ret = ff_rss_tbl_get_portrange (faddr .s_addr , laddr .s_addr , * fportp ,
606+ & rss_first , & rss_last , & rss_portrange );
607+ if (rss_ret < 0 ) {
608+ if (rss_ret != - ENOENT )
609+ rss_tbl_init = -1 ;
610+ } else {
611+ /* [0] store last port idx */
612+ rss_match = 1 ;
613+ count = rss_last - rss_first + 1 ;
614+ if (dorandom )
615+ rss_portrange [0 ] = rss_first + (arc4random () % (count ));
616+ }
617+ }
618+
619+ if (!rss_match ) {
620+ struct sockaddr_in ifp_sin ;
621+ bzero (& ifp_sin , sizeof (ifp_sin ));
622+ ifp_sin .sin_addr .s_addr = laddr .s_addr ;
623+ ifp_sin .sin_family = AF_INET ;
624+ ifp_sin .sin_len = sizeof (ifp_sin );
625+ ifa = ifa_ifwithnet ((struct sockaddr * )& ifp_sin , 0 , RT_ALL_FIBS );
626+ if (ifa == NULL ) {
627+
628+ ifp_sin .sin_addr .s_addr = faddr .s_addr ;
629+ ifa = ifa_ifwithnet ((struct sockaddr * )& ifp_sin , 0 , RT_ALL_FIBS );
630+ if ( ifa == NULL )
631+ return (EADDRNOTAVAIL );
632+ }
633+ ifp = ifa -> ifa_ifp ;
634+
635+ if (dorandom )
636+ * lastport = first + (arc4random () % (last - first ));
637+
638+ count = last - first ;
639+ }
640+
641+ do {
642+ if (count -- < 0 ) /* completely used? */
643+ return (EADDRNOTAVAIL );
644+ if (rss_match ) {
645+ rss_portrange [0 ]++ ;
646+ if (rss_portrange [0 ] < rss_first || rss_portrange [0 ] > rss_last )
647+ rss_portrange [0 ] = rss_first ;
648+ * lastport = rss_portrange [rss_portrange [0 ]];
649+ } else {
650+ ++ * lastport ;
651+ if (* lastport < first || * lastport > last )
652+ * lastport = first ;
653+ }
654+ lport = htons (* lastport );
655+
656+ #ifdef INET6
657+ if ((inp -> inp_vflag & INP_IPV6 ) != 0 )
658+ tmpinp = in6_pcblookup_local (pcbinfo ,
659+ & inp -> in6p_laddr , lport , lookupflags , cred );
660+ #endif
661+ #if defined(INET ) && defined(INET6 )
662+ else
663+ #endif
664+ #ifdef INET
665+ {
666+ tmpinp = in_pcblookup_local (pcbinfo , laddr ,
667+ lport , lookupflags , cred );
668+ if (!rss_match && tmpinp == NULL ) {
669+ int rss ;
670+ /* Note:
671+ * LOOPBACK not support rss.
672+ */
673+ if ((ifp -> if_softc == NULL ) && (ifp -> if_flags & IFF_LOOPBACK ))
674+ break ;
675+ rss = ff_rss_check (ifp -> if_softc , faddr .s_addr , laddr .s_addr ,
676+ * fportp , lport );
677+ if (rss )
678+ break ;
679+ else
680+ tmpinp ++ ; /* Set not NULL to find another lport */
681+ }
682+ }
683+ #endif
684+ } while (tmpinp != NULL );
685+
686+ * lportp = lport ;
687+
688+ return (0 );
689+ }
690+ #endif
691+
503692/*
504693 * Return cached socket options.
505694 */
@@ -1118,61 +1307,19 @@ in_pcbconnect_setup(struct inpcb *inp, struct sockaddr *nam,
11181307 * oinpp = oinp ;
11191308 return (EADDRINUSE );
11201309 }
1121- #ifndef FSTACK
1310+
11221311 if (lport == 0 ) {
1312+ #ifndef FSTACK
11231313 error = in_pcbbind_setup (inp , NULL , & laddr .s_addr , & lport ,
11241314 cred );
1315+ #else
1316+ error = ff_in_pcb_lport (inp , & laddr , & lport , & faddr , & fport ,
1317+ cred , INPLOOKUP_WILDCARD );
1318+ #endif
11251319 if (error )
11261320 return (error );
11271321 }
1128- #else
1129- if (lport == 0 )
1130- {
1131- struct ifaddr * ifa ;
1132- struct ifnet * ifp ;
1133- struct sockaddr_in ifp_sin ;
1134- unsigned loop_count = 0 ;
1135- bzero (& ifp_sin , sizeof (ifp_sin ));
1136- ifp_sin .sin_addr .s_addr = laddr .s_addr ;
1137- ifp_sin .sin_family = AF_INET ;
1138- ifp_sin .sin_len = sizeof (ifp_sin );
1139- ifa = ifa_ifwithnet ((struct sockaddr * )& ifp_sin , 0 , RT_ALL_FIBS );
1140- if (ifa == NULL ) {
1141- ifp_sin .sin_addr .s_addr = faddr .s_addr ;
1142- ifa = ifa_ifwithnet ((struct sockaddr * )& ifp_sin , 0 , RT_ALL_FIBS );
1143- if ( ifa == NULL )
1144- return (EADDRNOTAVAIL );
1145- }
1146- ifp = ifa -> ifa_ifp ;
1147- while (lport == 0 ) {
1148- int rss ;
1149- error = in_pcb_lport (inp , & laddr , & lport , cred , INPLOOKUP_WILDCARD );
1150- if (error )
1151- return (error );
1152- /* Note:
1153- * if ifp->if_softc is NULL, such as laddr config in lo.
1154- * just return. but maybe it can't receive response to this worker.
1155- */
1156- if (!ifp -> if_softc ) {
1157- break ;
1158- }
1159- rss = ff_rss_check (ifp -> if_softc , faddr .s_addr , laddr .s_addr ,
1160- fport , lport );
1161- if (rss ) {
1162- break ;
1163- }
1164- lport = 0 ;
1165- /* Note:
1166- * if all ports are completely used, just return.
1167- * this ugly code is not a correct way, it just lets loop quit.
1168- * we will fix it as soon as possible.
1169- */
1170- if (++ loop_count >= 65535 ) {
1171- return (EADDRNOTAVAIL );
1172- }
1173- }
1174- }
1175- #endif
1322+
11761323 * laddrp = laddr .s_addr ;
11771324 * lportp = lport ;
11781325 * faddrp = faddr .s_addr ;
0 commit comments