Page MenuHomeFreeBSD

D49142.diff
No OneTemporary

D49142.diff

diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h
--- a/sys/netinet/in_pcb.h
+++ b/sys/netinet/in_pcb.h
@@ -645,8 +645,6 @@
int in_pcbbind_setup(struct inpcb *, struct sockaddr_in *, in_addr_t *,
u_short *, int, struct ucred *);
int in_pcbconnect(struct inpcb *, struct sockaddr_in *, struct ucred *);
-int in_pcbconnect_setup(const struct inpcb *, struct sockaddr_in *,
- in_addr_t *, u_short *, in_addr_t *, u_short *, struct ucred *);
void in_pcbdisconnect(struct inpcb *);
void in_pcbdrop(struct inpcb *);
void in_pcbfree(struct inpcb *);
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1088,30 +1088,109 @@
int
in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
{
- u_short lport, fport;
- in_addr_t laddr, faddr;
- int anonport, error;
+ struct in_addr laddr, faddr;
+ u_short lport;
+ int error;
+ bool anonport;
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
KASSERT(in_nullhost(inp->inp_faddr),
("%s: inp is already connected", __func__));
+ KASSERT(sin->sin_family == AF_INET,
+ ("%s: invalid address family for %p", __func__, sin));
+ KASSERT(sin->sin_len == sizeof(*sin),
+ ("%s: invalid address length for %p", __func__, sin));
- lport = inp->inp_lport;
- laddr = inp->inp_laddr.s_addr;
- anonport = (lport == 0);
- error = in_pcbconnect_setup(inp, sin, &laddr, &lport, &faddr, &fport,
- cred);
- if (error)
- return (error);
+ if (sin->sin_port == 0)
+ return (EADDRNOTAVAIL);
+
+ anonport = (inp->inp_lport == 0);
+
+ if (__predict_false(in_broadcast(sin->sin_addr))) {
+ if (!V_connect_inaddr_wild || CK_STAILQ_EMPTY(&V_in_ifaddrhead))
+ return (ENETUNREACH);
+ /*
+ * If the destination address is INADDR_ANY, use the primary
+ * local address. If the supplied address is INADDR_BROADCAST,
+ * and the primary interface supports broadcast, choose the
+ * broadcast address for that interface.
+ */
+ if (in_nullhost(sin->sin_addr)) {
+ faddr =
+ IA_SIN(CK_STAILQ_FIRST(&V_in_ifaddrhead))->sin_addr;
+ if ((error = prison_get_ip4(cred, &faddr)) != 0)
+ return (error);
+ } else if (sin->sin_addr.s_addr == INADDR_BROADCAST) {
+ if (CK_STAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags
+ & IFF_BROADCAST)
+ faddr = satosin(&CK_STAILQ_FIRST(
+ &V_in_ifaddrhead)->ia_broadaddr)->sin_addr;
+ else
+ faddr = sin->sin_addr;
+ }
+ } else
+ faddr = sin->sin_addr;
+
+ if (in_nullhost(inp->inp_laddr)) {
+ error = in_pcbladdr(inp, &faddr, &laddr, cred);
+ /*
+ * If the destination address is multicast and an outgoing
+ * interface has been set as a multicast option, prefer the
+ * address of that interface as our source address.
+ */
+ if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
+ inp->inp_moptions != NULL &&
+ inp->inp_moptions->imo_multicast_ifp != NULL) {
+ struct ifnet *ifp =
+ inp->inp_moptions->imo_multicast_ifp;
+ struct in_ifaddr *ia;
+
+ CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
+ if (ia->ia_ifp == ifp &&
+ prison_check_ip4(cred,
+ &ia->ia_addr.sin_addr) == 0)
+ break;
+ }
+ if (ia == NULL)
+ return (EADDRNOTAVAIL);
+ laddr = ia->ia_addr.sin_addr;
+ error = 0;
+ }
+ if (error)
+ return (error);
+ } else
+ laddr = inp->inp_laddr;
+
+ if (anonport) {
+ struct sockaddr_in lsin = {
+ .sin_family = AF_INET,
+ .sin_addr = laddr,
+ };
+ struct sockaddr_in fsin = {
+ .sin_family = AF_INET,
+ .sin_addr = faddr,
+ };
+
+ error = in_pcb_lport_dest(inp, (struct sockaddr *)&lsin,
+ &lport, (struct sockaddr *)&fsin, sin->sin_port, cred,
+ INPLOOKUP_WILDCARD);
+ if (error)
+ return (error);
+ } else if (in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr,
+ sin->sin_port, laddr, inp->inp_lport, 0, M_NODOM, RT_ALL_FIBS) !=
+ NULL)
+ return (EADDRINUSE);
+ else
+ lport = inp->inp_lport;
- inp->inp_faddr.s_addr = faddr;
- inp->inp_fport = fport;
+ inp->inp_faddr = faddr;
+ inp->inp_fport = sin->sin_port;
/* Do the initial binding of the local address if required. */
if (inp->inp_laddr.s_addr == INADDR_ANY && inp->inp_lport == 0) {
inp->inp_lport = lport;
- inp->inp_laddr.s_addr = laddr;
+ inp->inp_laddr = laddr;
if (in_pcbinshash(inp) != 0) {
inp->inp_laddr.s_addr = inp->inp_faddr.s_addr =
INADDR_ANY;
@@ -1120,7 +1199,7 @@
}
} else {
inp->inp_lport = lport;
- inp->inp_laddr.s_addr = laddr;
+ inp->inp_laddr = laddr;
if ((inp->inp_flags & INP_INHASHLIST) != 0)
in_pcbrehash(inp);
else
@@ -1354,126 +1433,6 @@
return (error);
}
-/*
- * Set up for a connect from a socket to the specified address.
- * On entry, *laddrp and *lportp should contain the current local
- * address and port for the PCB; these are updated to the values
- * that should be placed in inp_laddr and inp_lport to complete
- * the connect.
- *
- * On success, *faddrp and *fportp will be set to the remote address
- * and port. These are not updated in the error case.
- */
-int
-in_pcbconnect_setup(const struct inpcb *inp, struct sockaddr_in *sin,
- in_addr_t *laddrp, u_short *lportp, in_addr_t *faddrp, u_short *fportp,
- struct ucred *cred)
-{
- struct in_ifaddr *ia;
- struct in_addr laddr, faddr;
- u_short lport, fport;
- int error;
-
- KASSERT(sin->sin_family == AF_INET,
- ("%s: invalid address family for %p", __func__, sin));
- KASSERT(sin->sin_len == sizeof(*sin),
- ("%s: invalid address length for %p", __func__, sin));
-
- /*
- * Because a global state change doesn't actually occur here, a read
- * lock is sufficient.
- */
- NET_EPOCH_ASSERT();
- INP_LOCK_ASSERT(inp);
- INP_HASH_LOCK_ASSERT(inp->inp_pcbinfo);
-
- if (sin->sin_port == 0)
- return (EADDRNOTAVAIL);
- laddr.s_addr = *laddrp;
- lport = *lportp;
- faddr = sin->sin_addr;
- fport = sin->sin_port;
- if (V_connect_inaddr_wild && !CK_STAILQ_EMPTY(&V_in_ifaddrhead)) {
- /*
- * If the destination address is INADDR_ANY,
- * use the primary local address.
- * If the supplied address is INADDR_BROADCAST,
- * and the primary interface supports broadcast,
- * choose the broadcast address for that interface.
- */
- if (faddr.s_addr == INADDR_ANY) {
- faddr =
- IA_SIN(CK_STAILQ_FIRST(&V_in_ifaddrhead))->sin_addr;
- if ((error = prison_get_ip4(cred, &faddr)) != 0)
- return (error);
- } else if (faddr.s_addr == (u_long)INADDR_BROADCAST) {
- if (CK_STAILQ_FIRST(&V_in_ifaddrhead)->ia_ifp->if_flags &
- IFF_BROADCAST)
- faddr = satosin(&CK_STAILQ_FIRST(
- &V_in_ifaddrhead)->ia_broadaddr)->sin_addr;
- }
- } else if (faddr.s_addr == INADDR_ANY) {
- return (ENETUNREACH);
- }
- if (laddr.s_addr == INADDR_ANY) {
- error = in_pcbladdr(inp, &faddr, &laddr, cred);
- /*
- * If the destination address is multicast and an outgoing
- * interface has been set as a multicast option, prefer the
- * address of that interface as our source address.
- */
- if (IN_MULTICAST(ntohl(faddr.s_addr)) &&
- inp->inp_moptions != NULL) {
- struct ip_moptions *imo;
- struct ifnet *ifp;
-
- imo = inp->inp_moptions;
- if (imo->imo_multicast_ifp != NULL) {
- ifp = imo->imo_multicast_ifp;
- CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
- if (ia->ia_ifp == ifp &&
- prison_check_ip4(cred,
- &ia->ia_addr.sin_addr) == 0)
- break;
- }
- if (ia == NULL)
- error = EADDRNOTAVAIL;
- else {
- laddr = ia->ia_addr.sin_addr;
- error = 0;
- }
- }
- }
- if (error)
- return (error);
- }
-
- if (lport != 0) {
- if (in_pcblookup_hash_locked(inp->inp_pcbinfo, faddr,
- fport, laddr, lport, 0, M_NODOM, RT_ALL_FIBS) != NULL)
- return (EADDRINUSE);
- } else {
- struct sockaddr_in lsin, fsin;
-
- 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,
- INPLOOKUP_WILDCARD);
- if (error)
- return (error);
- }
- *laddrp = laddr.s_addr;
- *lportp = lport;
- *faddrp = faddr.s_addr;
- *fportp = fport;
- return (0);
-}
-
void
in_pcbdisconnect(struct inpcb *inp)
{

File Metadata

Mime Type
text/plain
Expires
Fri, Feb 28, 4:03 AM (15 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16874207
Default Alt Text
D49142.diff (8 KB)

Event Timeline