Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/udp_usrreq.c
Show First 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | |||||
#else | #else | ||||
sizeof(struct sockaddr_in) | sizeof(struct sockaddr_in) | ||||
#endif | #endif | ||||
); /* 40 1K datagrams */ | ); /* 40 1K datagrams */ | ||||
SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, | SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, | ||||
&udp_recvspace, 0, "Maximum space for incoming UDP datagrams"); | &udp_recvspace, 0, "Maximum space for incoming UDP datagrams"); | ||||
VNET_DEFINE(struct inpcbhead, udb); /* from udp_var.h */ | |||||
VNET_DEFINE(struct inpcbinfo, udbinfo); | VNET_DEFINE(struct inpcbinfo, udbinfo); | ||||
VNET_DEFINE(struct inpcbhead, ulitecb); | |||||
VNET_DEFINE(struct inpcbinfo, ulitecbinfo); | VNET_DEFINE(struct inpcbinfo, ulitecbinfo); | ||||
VNET_DEFINE_STATIC(uma_zone_t, udpcb_zone); | VNET_DEFINE_STATIC(uma_zone_t, udpcb_zone); | ||||
#define V_udpcb_zone VNET(udpcb_zone) | #define V_udpcb_zone VNET(udpcb_zone) | ||||
#ifndef UDBHASHSIZE | #ifndef UDBHASHSIZE | ||||
#define UDBHASHSIZE 128 | #define UDBHASHSIZE 128 | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | udp_init(void) | ||||
/* | /* | ||||
* For now default to 2-tuple UDP hashing - until the fragment | * For now default to 2-tuple UDP hashing - until the fragment | ||||
* reassembly code can also update the flowid. | * reassembly code can also update the flowid. | ||||
* | * | ||||
* Once we can calculate the flowid that way and re-establish | * Once we can calculate the flowid that way and re-establish | ||||
* a 4-tuple, flip this to 4-tuple. | * a 4-tuple, flip this to 4-tuple. | ||||
*/ | */ | ||||
in_pcbinfo_init(&V_udbinfo, "udp", &V_udb, UDBHASHSIZE, UDBHASHSIZE, | in_pcbinfo_init(&V_udbinfo, "udp", UDBHASHSIZE, UDBHASHSIZE, | ||||
"udp_inpcb", udp_inpcb_init, IPI_HASHFIELDS_2TUPLE); | "udp_inpcb", udp_inpcb_init); | ||||
V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb), | V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb), | ||||
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); | ||||
uma_zone_set_max(V_udpcb_zone, maxsockets); | uma_zone_set_max(V_udpcb_zone, maxsockets); | ||||
uma_zone_set_warning(V_udpcb_zone, "kern.ipc.maxsockets limit reached"); | uma_zone_set_warning(V_udpcb_zone, "kern.ipc.maxsockets limit reached"); | ||||
EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL, | EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL, | ||||
EVENTHANDLER_PRI_ANY); | EVENTHANDLER_PRI_ANY); | ||||
} | } | ||||
void | void | ||||
udplite_init(void) | udplite_init(void) | ||||
{ | { | ||||
in_pcbinfo_init(&V_ulitecbinfo, "udplite", &V_ulitecb, UDBHASHSIZE, | in_pcbinfo_init(&V_ulitecbinfo, "udplite", UDBHASHSIZE, | ||||
UDBHASHSIZE, "udplite_inpcb", udplite_inpcb_init, | UDBHASHSIZE, "udplite_inpcb", udplite_inpcb_init); | ||||
IPI_HASHFIELDS_2TUPLE); | |||||
} | } | ||||
/* | /* | ||||
* Kernel module interface for updating udpstat. The argument is an index | * Kernel module interface for updating udpstat. The argument is an index | ||||
* into udpstat treated as an array of u_long. While this encodes the | * into udpstat treated as an array of u_long. While this encodes the | ||||
* general layout of udpstat into the caller, it doesn't encode its location, | * general layout of udpstat into the caller, it doesn't encode its location, | ||||
* so that future changes to add, for example, per-CPU stats support won't | * so that future changes to add, for example, per-CPU stats support won't | ||||
* cause binary compatibility problems for kernel modules. | * cause binary compatibility problems for kernel modules. | ||||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | if (sbappendaddr_locked(&so->so_rcv, append_sa, n, opts) == 0) { | ||||
if (opts) | if (opts) | ||||
m_freem(opts); | m_freem(opts); | ||||
UDPSTAT_INC(udps_fullsock); | UDPSTAT_INC(udps_fullsock); | ||||
} else | } else | ||||
sorwakeup_locked(so); | sorwakeup_locked(so); | ||||
return (0); | return (0); | ||||
} | } | ||||
static bool | |||||
udp_multi_match(const struct inpcb *inp, void *v) | |||||
{ | |||||
struct ip *ip = v; | |||||
struct udphdr *uh = (struct udphdr *)(ip + 1); | |||||
if (inp->inp_lport != uh->uh_dport) | |||||
return (false); | |||||
#ifdef INET6 | |||||
if ((inp->inp_vflag & INP_IPV4) == 0) | |||||
return (false); | |||||
#endif | |||||
if (inp->inp_laddr.s_addr != INADDR_ANY && | |||||
inp->inp_laddr.s_addr != ip->ip_dst.s_addr) | |||||
return (false); | |||||
if (inp->inp_faddr.s_addr != INADDR_ANY && | |||||
inp->inp_faddr.s_addr != ip->ip_src.s_addr) | |||||
return (false); | |||||
if (inp->inp_fport != 0 && | |||||
inp->inp_fport != uh->uh_sport) | |||||
return (false); | |||||
return (true); | |||||
} | |||||
static int | |||||
udp_multi_input(struct mbuf *m, int proto, struct sockaddr_in *udp_in) | |||||
{ | |||||
struct ip *ip = mtod(m, struct ip *); | |||||
struct inpcb_iterator inpi = INP_ITERATOR(udp_get_inpcbinfo(proto), | |||||
INPLOOKUP_RLOCKPCB, udp_multi_match, ip); | |||||
struct udphdr *uh = (struct udphdr *)(ip + 1); | |||||
struct inpcb *inp; | |||||
struct mbuf *n; | |||||
int appends = 0; | |||||
MPASS(ip->ip_hl == sizeof(struct ip) >> 2); | |||||
while ((inp = inp_next(&inpi)) != NULL) { | |||||
/* | |||||
* XXXRW: Because we weren't holding either the inpcb | |||||
* or the hash lock when we checked for a match | |||||
* before, we should probably recheck now that the | |||||
* inpcb lock is held. | |||||
*/ | |||||
/* | |||||
* Handle socket delivery policy for any-source | |||||
* and source-specific multicast. [RFC3678] | |||||
*/ | |||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { | |||||
struct ip_moptions *imo; | |||||
struct sockaddr_in group; | |||||
int blocked; | |||||
imo = inp->inp_moptions; | |||||
if (imo == NULL) | |||||
continue; | |||||
bzero(&group, sizeof(struct sockaddr_in)); | |||||
group.sin_len = sizeof(struct sockaddr_in); | |||||
group.sin_family = AF_INET; | |||||
group.sin_addr = ip->ip_dst; | |||||
blocked = imo_multi_filter(imo, m->m_pkthdr.rcvif, | |||||
(struct sockaddr *)&group, | |||||
(struct sockaddr *)&udp_in[0]); | |||||
if (blocked != MCAST_PASS) { | |||||
if (blocked == MCAST_NOTGMEMBER) | |||||
IPSTAT_INC(ips_notmember); | |||||
if (blocked == MCAST_NOTSMEMBER || | |||||
blocked == MCAST_MUTED) | |||||
UDPSTAT_INC(udps_filtermcast); | |||||
continue; | |||||
} | |||||
} | |||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != NULL) { | |||||
if (proto == IPPROTO_UDPLITE) | |||||
UDPLITE_PROBE(receive, NULL, inp, ip, inp, uh); | |||||
else | |||||
UDP_PROBE(receive, NULL, inp, ip, inp, uh); | |||||
if (udp_append(inp, ip, n, sizeof(struct ip), udp_in)) { | |||||
INP_RUNLOCK(inp); | |||||
break; | |||||
} else | |||||
appends++; | |||||
} | |||||
/* | |||||
* Don't look for additional matches if this one does | |||||
* not have either the SO_REUSEPORT or SO_REUSEADDR | |||||
* socket options set. This heuristic avoids | |||||
* searching through all pcbs in the common case of a | |||||
* non-shared port. It assumes that an application | |||||
* will never clear these options after setting them. | |||||
*/ | |||||
if ((inp->inp_socket->so_options & | |||||
(SO_REUSEPORT|SO_REUSEPORT_LB|SO_REUSEADDR)) == 0) { | |||||
INP_RUNLOCK(inp); | |||||
break; | |||||
} | |||||
} | |||||
m_freem(m); | |||||
if (appends == 0) { | |||||
/* | |||||
* No matching pcb found; discard datagram. (No need | |||||
* to send an ICMP Port Unreachable for a broadcast | |||||
* or multicast datgram.) | |||||
*/ | |||||
UDPSTAT_INC(udps_noport); | |||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) | |||||
UDPSTAT_INC(udps_noportmcast); | |||||
else | |||||
UDPSTAT_INC(udps_noportbcast); | |||||
} | |||||
return (IPPROTO_DONE); | |||||
} | |||||
int | int | ||||
udp_input(struct mbuf **mp, int *offp, int proto) | udp_input(struct mbuf **mp, int *offp, int proto) | ||||
{ | { | ||||
struct ip *ip; | struct ip *ip; | ||||
struct udphdr *uh; | struct udphdr *uh; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
uint16_t len, ip_len; | uint16_t len, ip_len; | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | if (uh->uh_sum) { | ||||
} else { | } else { | ||||
/* UDPLite requires a checksum */ | /* UDPLite requires a checksum */ | ||||
/* XXX: What is the right UDPLite MIB counter here? */ | /* XXX: What is the right UDPLite MIB counter here? */ | ||||
m_freem(m); | m_freem(m); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
} | } | ||||
} | } | ||||
pcbinfo = udp_get_inpcbinfo(proto); | |||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || | if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) || | ||||
in_broadcast(ip->ip_dst, ifp)) { | in_broadcast(ip->ip_dst, ifp)) | ||||
struct inpcb *last; | return (udp_multi_input(m, proto, udp_in)); | ||||
struct inpcbhead *pcblist; | |||||
NET_EPOCH_ASSERT(); | pcbinfo = udp_get_inpcbinfo(proto); | ||||
pcblist = udp_get_pcblist(proto); | |||||
last = NULL; | |||||
CK_LIST_FOREACH(inp, pcblist, inp_list) { | |||||
if (inp->inp_lport != uh->uh_dport) | |||||
continue; | |||||
#ifdef INET6 | |||||
if ((inp->inp_vflag & INP_IPV4) == 0) | |||||
continue; | |||||
#endif | |||||
if (inp->inp_laddr.s_addr != INADDR_ANY && | |||||
inp->inp_laddr.s_addr != ip->ip_dst.s_addr) | |||||
continue; | |||||
if (inp->inp_faddr.s_addr != INADDR_ANY && | |||||
inp->inp_faddr.s_addr != ip->ip_src.s_addr) | |||||
continue; | |||||
if (inp->inp_fport != 0 && | |||||
inp->inp_fport != uh->uh_sport) | |||||
continue; | |||||
INP_RLOCK(inp); | |||||
if (__predict_false(inp->inp_flags2 & INP_FREED)) { | |||||
INP_RUNLOCK(inp); | |||||
continue; | |||||
} | |||||
/* | /* | ||||
* XXXRW: Because we weren't holding either the inpcb | |||||
* or the hash lock when we checked for a match | |||||
* before, we should probably recheck now that the | |||||
* inpcb lock is held. | |||||
*/ | |||||
/* | |||||
* Handle socket delivery policy for any-source | |||||
* and source-specific multicast. [RFC3678] | |||||
*/ | |||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) { | |||||
struct ip_moptions *imo; | |||||
struct sockaddr_in group; | |||||
int blocked; | |||||
imo = inp->inp_moptions; | |||||
if (imo == NULL) { | |||||
INP_RUNLOCK(inp); | |||||
continue; | |||||
} | |||||
bzero(&group, sizeof(struct sockaddr_in)); | |||||
group.sin_len = sizeof(struct sockaddr_in); | |||||
group.sin_family = AF_INET; | |||||
group.sin_addr = ip->ip_dst; | |||||
blocked = imo_multi_filter(imo, ifp, | |||||
(struct sockaddr *)&group, | |||||
(struct sockaddr *)&udp_in[0]); | |||||
if (blocked != MCAST_PASS) { | |||||
if (blocked == MCAST_NOTGMEMBER) | |||||
IPSTAT_INC(ips_notmember); | |||||
if (blocked == MCAST_NOTSMEMBER || | |||||
blocked == MCAST_MUTED) | |||||
UDPSTAT_INC(udps_filtermcast); | |||||
INP_RUNLOCK(inp); | |||||
continue; | |||||
} | |||||
} | |||||
if (last != NULL) { | |||||
struct mbuf *n; | |||||
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) != | |||||
NULL) { | |||||
if (proto == IPPROTO_UDPLITE) | |||||
UDPLITE_PROBE(receive, NULL, last, ip, | |||||
last, uh); | |||||
else | |||||
UDP_PROBE(receive, NULL, last, ip, last, | |||||
uh); | |||||
if (udp_append(last, ip, n, iphlen, | |||||
udp_in)) { | |||||
INP_RUNLOCK(inp); | |||||
goto badunlocked; | |||||
} | |||||
} | |||||
/* Release PCB lock taken on previous pass. */ | |||||
INP_RUNLOCK(last); | |||||
} | |||||
last = inp; | |||||
/* | |||||
* Don't look for additional matches if this one does | |||||
* not have either the SO_REUSEPORT or SO_REUSEADDR | |||||
* socket options set. This heuristic avoids | |||||
* searching through all pcbs in the common case of a | |||||
* non-shared port. It assumes that an application | |||||
* will never clear these options after setting them. | |||||
*/ | |||||
if ((last->inp_socket->so_options & | |||||
(SO_REUSEPORT|SO_REUSEPORT_LB|SO_REUSEADDR)) == 0) | |||||
break; | |||||
} | |||||
if (last == NULL) { | |||||
/* | |||||
* No matching pcb found; discard datagram. (No need | |||||
* to send an ICMP Port Unreachable for a broadcast | |||||
* or multicast datgram.) | |||||
*/ | |||||
UDPSTAT_INC(udps_noport); | |||||
if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) | |||||
UDPSTAT_INC(udps_noportmcast); | |||||
else | |||||
UDPSTAT_INC(udps_noportbcast); | |||||
goto badunlocked; | |||||
} | |||||
if (proto == IPPROTO_UDPLITE) | |||||
UDPLITE_PROBE(receive, NULL, last, ip, last, uh); | |||||
else | |||||
UDP_PROBE(receive, NULL, last, ip, last, uh); | |||||
if (udp_append(last, ip, m, iphlen, udp_in) == 0) | |||||
INP_RUNLOCK(last); | |||||
return (IPPROTO_DONE); | |||||
} | |||||
/* | |||||
* Locate pcb for datagram. | * Locate pcb for datagram. | ||||
*/ | * | ||||
/* | |||||
* Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. | * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. | ||||
*/ | */ | ||||
if ((m->m_flags & M_IP_NEXTHOP) && | if ((m->m_flags & M_IP_NEXTHOP) && | ||||
(fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { | (fwd_tag = m_tag_find(m, PACKET_TAG_IPFORWARD, NULL)) != NULL) { | ||||
struct sockaddr_in *next_hop; | struct sockaddr_in *next_hop; | ||||
next_hop = (struct sockaddr_in *)(fwd_tag + 1); | next_hop = (struct sockaddr_in *)(fwd_tag + 1); | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | udplite_ctlinput(int cmd, struct sockaddr *sa, void *vip) | ||||
return (udp_common_ctlinput(cmd, sa, vip, &V_ulitecbinfo)); | return (udp_common_ctlinput(cmd, sa, vip, &V_ulitecbinfo)); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
static int | static int | ||||
udp_pcblist(SYSCTL_HANDLER_ARGS) | udp_pcblist(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct inpcb_iterator inpi = INP_ALL_ITERATOR(&V_udbinfo, | |||||
INPLOOKUP_RLOCKPCB); | |||||
struct xinpgen xig; | struct xinpgen xig; | ||||
struct epoch_tracker et; | |||||
struct inpcb *inp; | struct inpcb *inp; | ||||
int error; | int error; | ||||
if (req->newptr != 0) | if (req->newptr != 0) | ||||
return (EPERM); | return (EPERM); | ||||
if (req->oldptr == 0) { | if (req->oldptr == 0) { | ||||
int n; | int n; | ||||
Show All 11 Lines | udp_pcblist(SYSCTL_HANDLER_ARGS) | ||||
xig.xig_len = sizeof xig; | xig.xig_len = sizeof xig; | ||||
xig.xig_count = V_udbinfo.ipi_count; | xig.xig_count = V_udbinfo.ipi_count; | ||||
xig.xig_gen = V_udbinfo.ipi_gencnt; | xig.xig_gen = V_udbinfo.ipi_gencnt; | ||||
xig.xig_sogen = so_gencnt; | xig.xig_sogen = so_gencnt; | ||||
error = SYSCTL_OUT(req, &xig, sizeof xig); | error = SYSCTL_OUT(req, &xig, sizeof xig); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
NET_EPOCH_ENTER(et); | while ((inp = inp_next(&inpi)) != NULL) { | ||||
for (inp = CK_LIST_FIRST(V_udbinfo.ipi_listhead); | |||||
inp != NULL; | |||||
inp = CK_LIST_NEXT(inp, inp_list)) { | |||||
INP_RLOCK(inp); | |||||
if (inp->inp_gencnt <= xig.xig_gen && | if (inp->inp_gencnt <= xig.xig_gen && | ||||
cr_canseeinpcb(req->td->td_ucred, inp) == 0) { | cr_canseeinpcb(req->td->td_ucred, inp) == 0) { | ||||
struct xinpcb xi; | struct xinpcb xi; | ||||
in_pcbtoxinpcb(inp, &xi); | in_pcbtoxinpcb(inp, &xi); | ||||
INP_RUNLOCK(inp); | |||||
error = SYSCTL_OUT(req, &xi, sizeof xi); | error = SYSCTL_OUT(req, &xi, sizeof xi); | ||||
if (error) | if (error) { | ||||
break; | |||||
} else | |||||
INP_RUNLOCK(inp); | INP_RUNLOCK(inp); | ||||
break; | |||||
} | } | ||||
NET_EPOCH_EXIT(et); | } | ||||
} | |||||
if (!error) { | if (!error) { | ||||
/* | /* | ||||
* Give the user an updated idea of our state. If the | * Give the user an updated idea of our state. If the | ||||
* generation differs from what we told her before, she knows | * generation differs from what we told her before, she knows | ||||
* that something happened while we were processing this | * that something happened while we were processing this | ||||
* request, and it might be necessary to retry. | * request, and it might be necessary to retry. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 369 Lines • ▼ Show 20 Lines | #endif /* RSS */ | ||||
/* | /* | ||||
* If the IP_SENDSRCADDR control message was specified, override the | * If the IP_SENDSRCADDR control message was specified, override the | ||||
* source address for this datagram. Its use is invalidated if the | * source address for this datagram. Its use is invalidated if the | ||||
* address thus specified is incomplete or clobbers other inpcbs. | * address thus specified is incomplete or clobbers other inpcbs. | ||||
*/ | */ | ||||
laddr = inp->inp_laddr; | laddr = inp->inp_laddr; | ||||
lport = inp->inp_lport; | lport = inp->inp_lport; | ||||
if (src.sin_family == AF_INET) { | if (src.sin_family == AF_INET) { | ||||
INP_HASH_LOCK_ASSERT(pcbinfo); | |||||
if ((lport == 0) || | if ((lport == 0) || | ||||
(laddr.s_addr == INADDR_ANY && | (laddr.s_addr == INADDR_ANY && | ||||
src.sin_addr.s_addr == INADDR_ANY)) { | src.sin_addr.s_addr == INADDR_ANY)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
goto release; | goto release; | ||||
} | } | ||||
INP_HASH_WLOCK(pcbinfo); | |||||
error = in_pcbbind_setup(inp, (struct sockaddr *)&src, | error = in_pcbbind_setup(inp, (struct sockaddr *)&src, | ||||
&laddr.s_addr, &lport, td->td_ucred); | &laddr.s_addr, &lport, td->td_ucred); | ||||
INP_HASH_WUNLOCK(pcbinfo); | |||||
if (error) | if (error) | ||||
goto release; | goto release; | ||||
} | } | ||||
/* | /* | ||||
* If a UDP socket has been connected, then a local address/port will | * If a UDP socket has been connected, then a local address/port will | ||||
* have been selected and bound. | * have been selected and bound. | ||||
* | * | ||||
Show All 26 Lines | if (sin != NULL) { | ||||
* | * | ||||
* If we already have a valid binding and we're not | * If we already have a valid binding and we're not | ||||
* requesting a destination address rewrite, use a fast path. | * requesting a destination address rewrite, use a fast path. | ||||
*/ | */ | ||||
if (inp->inp_laddr.s_addr == INADDR_ANY || | if (inp->inp_laddr.s_addr == INADDR_ANY || | ||||
inp->inp_lport == 0 || | inp->inp_lport == 0 || | ||||
sin->sin_addr.s_addr == INADDR_ANY || | sin->sin_addr.s_addr == INADDR_ANY || | ||||
sin->sin_addr.s_addr == INADDR_BROADCAST) { | sin->sin_addr.s_addr == INADDR_BROADCAST) { | ||||
INP_HASH_LOCK_ASSERT(pcbinfo); | INP_HASH_WLOCK(pcbinfo); | ||||
error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, | error = in_pcbconnect_setup(inp, addr, &laddr.s_addr, | ||||
&lport, &faddr.s_addr, &fport, NULL, | &lport, &faddr.s_addr, &fport, NULL, | ||||
td->td_ucred); | td->td_ucred); | ||||
if (error) | if (error) { | ||||
INP_HASH_WUNLOCK(pcbinfo); | |||||
goto release; | goto release; | ||||
} | |||||
/* | /* | ||||
* XXXRW: Why not commit the port if the address is | * XXXRW: Why not commit the port if the address is | ||||
* !INADDR_ANY? | * !INADDR_ANY? | ||||
*/ | */ | ||||
/* Commit the local port if newly assigned. */ | /* Commit the local port if newly assigned. */ | ||||
if (inp->inp_laddr.s_addr == INADDR_ANY && | if (inp->inp_laddr.s_addr == INADDR_ANY && | ||||
inp->inp_lport == 0) { | inp->inp_lport == 0) { | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
/* | /* | ||||
* Remember addr if jailed, to prevent | * Remember addr if jailed, to prevent | ||||
* rebinding. | * rebinding. | ||||
*/ | */ | ||||
if (prison_flag(td->td_ucred, PR_IP4)) | if (prison_flag(td->td_ucred, PR_IP4)) | ||||
inp->inp_laddr = laddr; | inp->inp_laddr = laddr; | ||||
inp->inp_lport = lport; | inp->inp_lport = lport; | ||||
INP_HASH_WLOCK(pcbinfo); | |||||
error = in_pcbinshash(inp); | error = in_pcbinshash(inp); | ||||
INP_HASH_WUNLOCK(pcbinfo); | INP_HASH_WUNLOCK(pcbinfo); | ||||
if (error != 0) { | if (error != 0) { | ||||
inp->inp_lport = 0; | inp->inp_lport = 0; | ||||
error = EAGAIN; | error = EAGAIN; | ||||
goto release; | goto release; | ||||
} | } | ||||
inp->inp_flags |= INP_ANONPORT; | inp->inp_flags |= INP_ANONPORT; | ||||
} | } else | ||||
INP_HASH_WUNLOCK(pcbinfo); | |||||
} else { | } else { | ||||
faddr = sin->sin_addr; | faddr = sin->sin_addr; | ||||
fport = sin->sin_port; | fport = sin->sin_port; | ||||
} | } | ||||
} else { | } else { | ||||
INP_LOCK_ASSERT(inp); | INP_LOCK_ASSERT(inp); | ||||
faddr = inp->inp_faddr; | faddr = inp->inp_faddr; | ||||
fport = inp->inp_fport; | fport = inp->inp_fport; | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | udp_attach(struct socket *so, int proto, struct thread *td) | ||||
int error; | int error; | ||||
pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); | pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
KASSERT(inp == NULL, ("udp_attach: inp != NULL")); | KASSERT(inp == NULL, ("udp_attach: inp != NULL")); | ||||
error = soreserve(so, udp_sendspace, udp_recvspace); | error = soreserve(so, udp_sendspace, udp_recvspace); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
INP_INFO_WLOCK(pcbinfo); | |||||
error = in_pcballoc(so, pcbinfo); | error = in_pcballoc(so, pcbinfo); | ||||
if (error) { | if (error) | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
return (error); | return (error); | ||||
} | |||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
inp->inp_vflag |= INP_IPV4; | inp->inp_vflag |= INP_IPV4; | ||||
inp->inp_ip_ttl = V_ip_defttl; | inp->inp_ip_ttl = V_ip_defttl; | ||||
inp->inp_flowid = atomic_fetchadd_int(&udp_flowid, 1); | inp->inp_flowid = atomic_fetchadd_int(&udp_flowid, 1); | ||||
inp->inp_flowtype = M_HASHTYPE_OPAQUE; | inp->inp_flowtype = M_HASHTYPE_OPAQUE; | ||||
error = udp_newudpcb(inp); | error = udp_newudpcb(inp); | ||||
if (error) { | if (error) { | ||||
in_pcbdetach(inp); | in_pcbdetach(inp); | ||||
in_pcbfree(inp); | in_pcbfree(inp); | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
return (error); | return (error); | ||||
} | } | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
return (0); | return (0); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
int | int | ||||
udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f, udp_tun_icmp_t i, void *ctx) | udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f, udp_tun_icmp_t i, void *ctx) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
▲ Show 20 Lines • Show All 119 Lines • ▼ Show 20 Lines | udp_detach(struct socket *so) | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
struct udpcb *up; | struct udpcb *up; | ||||
pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); | pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol); | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
KASSERT(inp != NULL, ("udp_detach: inp == NULL")); | KASSERT(inp != NULL, ("udp_detach: inp == NULL")); | ||||
KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, | KASSERT(inp->inp_faddr.s_addr == INADDR_ANY, | ||||
("udp_detach: not disconnected")); | ("udp_detach: not disconnected")); | ||||
INP_INFO_WLOCK(pcbinfo); | |||||
INP_WLOCK(inp); | INP_WLOCK(inp); | ||||
up = intoudpcb(inp); | up = intoudpcb(inp); | ||||
KASSERT(up != NULL, ("%s: up == NULL", __func__)); | KASSERT(up != NULL, ("%s: up == NULL", __func__)); | ||||
inp->inp_ppcb = NULL; | inp->inp_ppcb = NULL; | ||||
in_pcbdetach(inp); | in_pcbdetach(inp); | ||||
in_pcbfree(inp); | in_pcbfree(inp); | ||||
INP_INFO_WUNLOCK(pcbinfo); | |||||
udp_discardcb(up); | udp_discardcb(up); | ||||
} | } | ||||
static int | static int | ||||
udp_disconnect(struct socket *so) | udp_disconnect(struct socket *so) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
▲ Show 20 Lines • Show All 78 Lines • Show Last 20 Lines |