Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/in_pcb.c
Show First 20 Lines • Show All 604 Lines • ▼ Show 20 Lines | if (in_pcbinshash(inp) != 0) { | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | } | ||||
if (anonport) | if (anonport) | ||||
inp->inp_flags |= INP_ANONPORT; | inp->inp_flags |= INP_ANONPORT; | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif | #endif | ||||
#if defined(INET) || defined(INET6) | |||||
/* | /* | ||||
* Select a local port (number) to use. | * Assign a local port like in_pcb_lport(), but also used with connect() | ||||
* and a foreign address and port. If fsa is non-NULL, choose a local port | |||||
* that is unused with those, otherwise one that is completely unused. | |||||
*/ | */ | ||||
#if defined(INET) || defined(INET6) | |||||
int | int | ||||
in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, | in_pcb_lport_dest(struct inpcb *inp, struct sockaddr *lsa, u_short *lportp, | ||||
struct ucred *cred, int lookupflags) | struct sockaddr *fsa, u_short fport, struct ucred *cred, int lookupflags) | ||||
{ | { | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
struct inpcb *tmpinp; | struct inpcb *tmpinp; | ||||
unsigned short *lastport; | unsigned short *lastport; | ||||
int count, dorandom, error; | int count, dorandom, error; | ||||
u_short aux, first, last, lport; | u_short aux, first, last, lport; | ||||
#ifdef INET | #ifdef INET | ||||
struct in_addr laddr; | struct in_addr laddr, faddr; | ||||
#endif | #endif | ||||
#ifdef INET6 | |||||
struct in6_addr *laddr6, *faddr6; | |||||
#endif | |||||
pcbinfo = inp->inp_pcbinfo; | pcbinfo = inp->inp_pcbinfo; | ||||
/* | /* | ||||
* Because no actual state changes occur here, a global write lock on | * Because no actual state changes occur here, a global write lock on | ||||
* the pcbinfo isn't required. | * the pcbinfo isn't required. | ||||
*/ | */ | ||||
INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
if (first > last) { | if (first > last) { | ||||
aux = first; | aux = first; | ||||
first = last; | first = last; | ||||
last = aux; | last = aux; | ||||
} | } | ||||
#ifdef INET | #ifdef INET | ||||
/* Make the compiler happy. */ | laddr.s_addr = INADDR_ANY; | ||||
laddr.s_addr = 0; | |||||
if ((inp->inp_vflag & (INP_IPV4|INP_IPV6)) == INP_IPV4) { | if ((inp->inp_vflag & (INP_IPV4|INP_IPV6)) == INP_IPV4) { | ||||
KASSERT(laddrp != NULL, ("%s: laddrp NULL for v4 inp %p", | laddr = ((struct sockaddr_in *)lsa)->sin_addr; | ||||
__func__, inp)); | if (fsa != NULL) | ||||
laddr = *laddrp; | faddr = ((struct sockaddr_in *)fsa)->sin_addr; | ||||
} | } | ||||
#endif | #endif | ||||
tmpinp = NULL; /* Make compiler happy. */ | #ifdef INET6 | ||||
if (lsa->sa_family == AF_INET6) { | |||||
laddr6 = &((struct sockaddr_in6 *)lsa)->sin6_addr; | |||||
if (fsa != NULL) | |||||
faddr6 = &((struct sockaddr_in6 *)fsa)->sin6_addr; | |||||
} | |||||
#endif | |||||
tmpinp = NULL; | |||||
lport = *lportp; | lport = *lportp; | ||||
if (dorandom) | if (dorandom) | ||||
*lastport = first + (arc4random() % (last - first)); | *lastport = first + (arc4random() % (last - first)); | ||||
count = last - first; | count = last - first; | ||||
do { | do { | ||||
if (count-- < 0) /* completely used? */ | if (count-- < 0) /* completely used? */ | ||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||
++*lastport; | ++*lastport; | ||||
if (*lastport < first || *lastport > last) | if (*lastport < first || *lastport > last) | ||||
*lastport = first; | *lastport = first; | ||||
lport = htons(*lastport); | lport = htons(*lastport); | ||||
if (fsa != NULL) { | |||||
#ifdef INET | |||||
if (lsa->sa_family == AF_INET) { | |||||
tmpinp = in_pcblookup_hash_locked(pcbinfo, | |||||
faddr, fport, laddr, lport, 0, NULL); | |||||
} | |||||
#endif | |||||
#ifdef INET6 | #ifdef INET6 | ||||
if (lsa->sa_family == AF_INET6) { | |||||
tmpinp = in6_pcblookup_hash_locked(pcbinfo, | |||||
faddr6, fport, laddr6, lport, 0, NULL); | |||||
} | |||||
#endif | |||||
} else { | |||||
#ifdef INET6 | |||||
if ((inp->inp_vflag & INP_IPV6) != 0) | if ((inp->inp_vflag & INP_IPV6) != 0) | ||||
tmpinp = in6_pcblookup_local(pcbinfo, | tmpinp = in6_pcblookup_local(pcbinfo, | ||||
&inp->in6p_laddr, lport, lookupflags, cred); | &inp->in6p_laddr, lport, lookupflags, cred); | ||||
#endif | #endif | ||||
#if defined(INET) && defined(INET6) | #if defined(INET) && defined(INET6) | ||||
else | else | ||||
#endif | #endif | ||||
#ifdef INET | #ifdef INET | ||||
tmpinp = in_pcblookup_local(pcbinfo, laddr, | tmpinp = in_pcblookup_local(pcbinfo, laddr, | ||||
lport, lookupflags, cred); | lport, lookupflags, cred); | ||||
#endif | #endif | ||||
} | |||||
} while (tmpinp != NULL); | } while (tmpinp != NULL); | ||||
#ifdef INET | |||||
if ((inp->inp_vflag & (INP_IPV4|INP_IPV6)) == INP_IPV4) | |||||
laddrp->s_addr = laddr.s_addr; | |||||
#endif | |||||
*lportp = lport; | *lportp = lport; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Select a local port (number) to use. | |||||
*/ | |||||
int | |||||
in_pcb_lport(struct inpcb *inp, struct in_addr *laddrp, u_short *lportp, | |||||
struct ucred *cred, int lookupflags) | |||||
{ | |||||
struct sockaddr_in laddr; | |||||
if (laddrp) { | |||||
bzero(&laddr, sizeof(laddr)); | |||||
laddr.sin_family = AF_INET; | |||||
laddr.sin_addr = *laddrp; | |||||
} | |||||
return (in_pcb_lport_dest(inp, laddrp ? (struct sockaddr *) &laddr : | |||||
NULL, lportp, NULL, 0, cred, lookupflags)); | |||||
} | |||||
/* | |||||
* Return cached socket options. | * Return cached socket options. | ||||
*/ | */ | ||||
int | int | ||||
inp_so_options(const struct inpcb *inp) | inp_so_options(const struct inpcb *inp) | ||||
{ | { | ||||
int so_options; | int so_options; | ||||
so_options = 0; | so_options = 0; | ||||
▲ Show 20 Lines • Show All 595 Lines • ▼ Show 20 Lines | if (IN_MULTICAST(ntohl(faddr.s_addr)) && | ||||
error = 0; | error = 0; | ||||
} | } | ||||
IN_IFADDR_RUNLOCK(&in_ifa_tracker); | IN_IFADDR_RUNLOCK(&in_ifa_tracker); | ||||
} | } | ||||
} | } | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
oinp = in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr, fport, | if (lport != 0) { | ||||
laddr, lport, 0, NULL); | oinp = in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr, | ||||
fport, laddr, lport, 0, NULL); | |||||
if (oinp != NULL) { | if (oinp != NULL) { | ||||
if (oinpp != NULL) | if (oinpp != NULL) | ||||
*oinpp = oinp; | *oinpp = oinp; | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} | } | ||||
if (lport == 0) { | } else { | ||||
error = in_pcbbind_setup(inp, NULL, &laddr.s_addr, &lport, | struct sockaddr_in lsin, fsin; | ||||
cred); | |||||
bzero(&lsin, sizeof(lsin)); | |||||
bzero(&fsin, sizeof(fsin)); | |||||
lsin.sin_family = AF_INET; | |||||
lsin.sin_addr = laddr; | |||||
fsin.sin_family = AF_INET; | |||||
fsin.sin_addr = faddr; | |||||
error = in_pcb_lport_dest(inp, (struct sockaddr *) &lsin, | |||||
&lport, (struct sockaddr *)& fsin, fport, cred, 0); | |||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
*laddrp = laddr.s_addr; | *laddrp = laddr.s_addr; | ||||
*lportp = lport; | *lportp = lport; | ||||
*faddrp = faddr.s_addr; | *faddrp = faddr.s_addr; | ||||
*fportp = fport; | *fportp = fport; | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 2,107 Lines • Show Last 20 Lines |