summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/udp_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/udp_usrreq.c')
-rw-r--r--freebsd/sys/netinet/udp_usrreq.c105
1 files changed, 68 insertions, 37 deletions
diff --git a/freebsd/sys/netinet/udp_usrreq.c b/freebsd/sys/netinet/udp_usrreq.c
index 178a8d5e..9557c154 100644
--- a/freebsd/sys/netinet/udp_usrreq.c
+++ b/freebsd/sys/netinet/udp_usrreq.c
@@ -150,7 +150,7 @@ VNET_DEFINE(struct inpcbhead, udb); /* from udp_var.h */
VNET_DEFINE(struct inpcbinfo, udbinfo);
VNET_DEFINE(struct inpcbhead, ulitecb);
VNET_DEFINE(struct inpcbinfo, ulitecbinfo);
-static VNET_DEFINE(uma_zone_t, udpcb_zone);
+VNET_DEFINE_STATIC(uma_zone_t, udpcb_zone);
#define V_udpcb_zone VNET(udpcb_zone)
#ifndef UDBHASHSIZE
@@ -405,6 +405,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
struct sockaddr_in udp_in[2];
struct mbuf *m;
struct m_tag *fwd_tag;
+ struct epoch_tracker et;
int cscov_partial, iphlen;
m = *mp;
@@ -535,10 +536,10 @@ udp_input(struct mbuf **mp, int *offp, int proto)
struct inpcbhead *pcblist;
struct ip_moptions *imo;
- INP_INFO_RLOCK(pcbinfo);
+ INP_INFO_RLOCK_ET(pcbinfo, et);
pcblist = udp_get_pcblist(proto);
last = NULL;
- LIST_FOREACH(inp, pcblist, inp_list) {
+ CK_LIST_FOREACH(inp, pcblist, inp_list) {
if (inp->inp_lport != uh->uh_dport)
continue;
#ifdef INET6
@@ -599,8 +600,12 @@ udp_input(struct mbuf **mp, int *offp, int proto)
if ((n = m_copym(m, 0, M_COPYALL, M_NOWAIT)) !=
NULL) {
- UDP_PROBE(receive, NULL, last, ip,
- last, uh);
+ 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)) {
goto inp_lost;
@@ -618,7 +623,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
* will never clear these options after setting them.
*/
if ((last->inp_socket->so_options &
- (SO_REUSEPORT|SO_REUSEADDR)) == 0)
+ (SO_REUSEPORT|SO_REUSEPORT_LB|SO_REUSEADDR)) == 0)
break;
}
@@ -631,14 +636,17 @@ udp_input(struct mbuf **mp, int *offp, int proto)
UDPSTAT_INC(udps_noportbcast);
if (inp)
INP_RUNLOCK(inp);
- INP_INFO_RUNLOCK(pcbinfo);
+ INP_INFO_RUNLOCK_ET(pcbinfo, et);
goto badunlocked;
}
- UDP_PROBE(receive, NULL, last, ip, last, uh);
+ 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);
inp_lost:
- INP_INFO_RUNLOCK(pcbinfo);
+ INP_INFO_RUNLOCK_ET(pcbinfo, et);
return (IPPROTO_DONE);
}
@@ -690,6 +698,10 @@ udp_input(struct mbuf **mp, int *offp, int proto)
inet_ntoa_r(ip->ip_dst, dst), ntohs(uh->uh_dport),
inet_ntoa_r(ip->ip_src, src), ntohs(uh->uh_sport));
}
+ if (proto == IPPROTO_UDPLITE)
+ UDPLITE_PROBE(receive, NULL, NULL, ip, NULL, uh);
+ else
+ UDP_PROBE(receive, NULL, NULL, ip, NULL, uh);
UDPSTAT_INC(udps_noport);
if (m->m_flags & (M_BCAST | M_MCAST)) {
UDPSTAT_INC(udps_noportbcast);
@@ -709,6 +721,10 @@ udp_input(struct mbuf **mp, int *offp, int proto)
*/
INP_RLOCK_ASSERT(inp);
if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl) {
+ if (proto == IPPROTO_UDPLITE)
+ UDPLITE_PROBE(receive, NULL, inp, ip, inp, uh);
+ else
+ UDP_PROBE(receive, NULL, inp, ip, inp, uh);
INP_RUNLOCK(inp);
m_freem(m);
return (IPPROTO_DONE);
@@ -724,7 +740,10 @@ udp_input(struct mbuf **mp, int *offp, int proto)
}
}
- UDP_PROBE(receive, NULL, inp, ip, inp, uh);
+ 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, m, iphlen, udp_in) == 0)
INP_RUNLOCK(inp);
return (IPPROTO_DONE);
@@ -808,14 +827,15 @@ udp_common_ctlinput(int cmd, struct sockaddr *sa, void *vip,
INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, NULL);
if (inp != NULL) {
struct udpcb *up;
+ void *ctx;
+ udp_tun_icmp_t func;
up = intoudpcb(inp);
- if (up->u_icmp_func != NULL) {
- INP_RUNLOCK(inp);
- (*up->u_icmp_func)(cmd, sa, vip, up->u_tun_ctx);
- } else {
- INP_RUNLOCK(inp);
- }
+ ctx = up->u_tun_ctx;
+ func = up->u_icmp_func;
+ INP_RUNLOCK(inp);
+ if (func != NULL)
+ (*func)(cmd, sa, vip, ctx);
}
}
} else
@@ -842,9 +862,9 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
{
int error, i, n;
struct inpcb *inp, **inp_list;
- struct in_pcblist *il;
inp_gen_t gencnt;
struct xinpgen xig;
+ struct epoch_tracker et;
/*
* The process of preparing the PCB list is too time-consuming and
@@ -863,10 +883,10 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
/*
* OK, now we're committed to doing something.
*/
- INP_INFO_RLOCK(&V_udbinfo);
+ INP_INFO_RLOCK_ET(&V_udbinfo, et);
gencnt = V_udbinfo.ipi_gencnt;
n = V_udbinfo.ipi_count;
- INP_INFO_RUNLOCK(&V_udbinfo);
+ INP_INFO_RUNLOCK_ET(&V_udbinfo, et);
error = sysctl_wire_old_buffer(req, 2 * (sizeof xig)
+ n * sizeof(struct xinpcb));
@@ -880,12 +900,14 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
error = SYSCTL_OUT(req, &xig, sizeof xig);
if (error)
return (error);
- il = malloc(sizeof(struct in_pcblist) + n * sizeof(struct inpcb *), M_TEMP, M_WAITOK|M_ZERO_INVARIANTS);
- inp_list = il->il_inp_list;
- INP_INFO_RLOCK(&V_udbinfo);
- for (inp = LIST_FIRST(V_udbinfo.ipi_listhead), i = 0; inp && i < n;
- inp = LIST_NEXT(inp, inp_list)) {
+ inp_list = malloc(n * sizeof *inp_list, M_TEMP, M_WAITOK);
+ if (inp_list == NULL)
+ return (ENOMEM);
+
+ INP_INFO_RLOCK_ET(&V_udbinfo, et);
+ for (inp = CK_LIST_FIRST(V_udbinfo.ipi_listhead), i = 0; inp && i < n;
+ inp = CK_LIST_NEXT(inp, inp_list)) {
INP_WLOCK(inp);
if (inp->inp_gencnt <= gencnt &&
cr_canseeinpcb(req->td->td_ucred, inp) == 0) {
@@ -894,7 +916,7 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
}
INP_WUNLOCK(inp);
}
- INP_INFO_RUNLOCK(&V_udbinfo);
+ INP_INFO_RUNLOCK_ET(&V_udbinfo, et);
n = i;
error = 0;
@@ -910,9 +932,14 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
} else
INP_RUNLOCK(inp);
}
- il->il_count = n;
- il->il_pcbinfo = &V_udbinfo;
- epoch_call(net_epoch_preempt, &il->il_epoch_ctx, in_pcblist_rele_rlocked);
+ INP_INFO_WLOCK(&V_udbinfo);
+ for (i = 0; i < n; i++) {
+ inp = inp_list[i];
+ INP_RLOCK(inp);
+ if (!in_pcbrele_rlocked(inp))
+ INP_RUNLOCK(inp);
+ }
+ INP_INFO_WUNLOCK(&V_udbinfo);
if (!error) {
/*
@@ -921,13 +948,14 @@ udp_pcblist(SYSCTL_HANDLER_ARGS)
* that something happened while we were processing this
* request, and it might be necessary to retry.
*/
- INP_INFO_RLOCK(&V_udbinfo);
+ INP_INFO_RLOCK_ET(&V_udbinfo, et);
xig.xig_gen = V_udbinfo.ipi_gencnt;
xig.xig_sogen = so_gencnt;
xig.xig_count = V_udbinfo.ipi_count;
- INP_INFO_RUNLOCK(&V_udbinfo);
+ INP_INFO_RUNLOCK_ET(&V_udbinfo, et);
error = SYSCTL_OUT(req, &xig, sizeof xig);
}
+ free(inp_list, M_TEMP);
return (error);
}
@@ -1106,6 +1134,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
struct cmsghdr *cm;
struct inpcbinfo *pcbinfo;
struct sockaddr_in *sin, src;
+ struct epoch_tracker et;
int cscov_partial = 0;
int error = 0;
int ipflags;
@@ -1262,7 +1291,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
(inp->inp_laddr.s_addr == INADDR_ANY) ||
(inp->inp_lport == 0))) ||
(src.sin_family == AF_INET)) {
- INP_HASH_RLOCK(pcbinfo);
+ INP_HASH_RLOCK_ET(pcbinfo, et);
unlock_udbinfo = UH_RLOCKED;
} else
unlock_udbinfo = UH_UNLOCKED;
@@ -1390,6 +1419,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
*/
ui = mtod(m, struct udpiphdr *);
bzero(ui->ui_x1, sizeof(ui->ui_x1)); /* XXX still needed? */
+ ui->ui_v = IPVERSION << 4;
ui->ui_pr = pr;
ui->ui_src = laddr;
ui->ui_dst = faddr;
@@ -1412,8 +1442,7 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
* the entire UDPLite packet is covered by the checksum.
*/
cscov_partial = (cscov == 0) ? 0 : 1;
- } else
- ui->ui_v = IPVERSION << 4;
+ }
/*
* Set the Don't Fragment bit in the IP header.
@@ -1518,8 +1547,11 @@ udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr,
if (unlock_udbinfo == UH_WLOCKED)
INP_HASH_WUNLOCK(pcbinfo);
else if (unlock_udbinfo == UH_RLOCKED)
- INP_HASH_RUNLOCK(pcbinfo);
- UDP_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
+ INP_HASH_RUNLOCK_ET(pcbinfo, et);
+ if (pr == IPPROTO_UDPLITE)
+ UDPLITE_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
+ else
+ UDP_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
error = ip_output(m, inp->inp_options,
(unlock_inp == UH_WLOCKED ? &inp->inp_route : NULL), ipflags,
inp->inp_moptions, inp);
@@ -1538,7 +1570,7 @@ release:
} else if (unlock_udbinfo == UH_RLOCKED) {
KASSERT(unlock_inp == UH_RLOCKED,
("%s: shared udbinfo lock, excl inp lock", __func__));
- INP_HASH_RUNLOCK(pcbinfo);
+ INP_HASH_RUNLOCK_ET(pcbinfo, et);
INP_RUNLOCK(inp);
} else if (unlock_inp == UH_WLOCKED)
INP_WUNLOCK(inp);
@@ -1719,7 +1751,6 @@ udp_detach(struct socket *so)
INP_WLOCK(inp);
up = intoudpcb(inp);
KASSERT(up != NULL, ("%s: up == NULL", __func__));
- /* XXX defer to epoch_call */
inp->inp_ppcb = NULL;
in_pcbdetach(inp);
in_pcbfree(inp);