Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/udp_usrreq.c
Show First 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | SYSCTL_VNET_PCPUSTAT(_net_inet_udp, UDPCTL_STATS, stats, struct udpstat, | ||||
udpstat, "UDP statistics (struct udpstat, netinet/udp_var.h)"); | udpstat, "UDP statistics (struct udpstat, netinet/udp_var.h)"); | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
VNET_PCPUSTAT_SYSUNINIT(udpstat); | VNET_PCPUSTAT_SYSUNINIT(udpstat); | ||||
#endif /* VIMAGE */ | #endif /* VIMAGE */ | ||||
#ifdef INET | #ifdef INET | ||||
static void udp_detach(struct socket *so); | static void udp_detach(struct socket *so); | ||||
static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *, | static int udp_output(struct inpcb *, struct mbuf *, struct sockaddr *, | ||||
struct mbuf *, struct thread *); | struct mbuf *, struct thread *, int); | ||||
#endif | #endif | ||||
static void | static void | ||||
udp_zone_change(void *tag) | udp_zone_change(void *tag) | ||||
{ | { | ||||
uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets); | uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets); | ||||
uma_zone_set_max(V_udpcb_zone, maxsockets); | uma_zone_set_max(V_udpcb_zone, maxsockets); | ||||
▲ Show 20 Lines • Show All 903 Lines • ▼ Show 20 Lines | default: | ||||
break; | break; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef INET | #ifdef INET | ||||
#ifdef INET6 | |||||
/* The logic here is derived from ip6_setpktopt(). See comments there. */ | |||||
static int | static int | ||||
udp_v4mapped_pktinfo(struct cmsghdr *cm, struct sockaddr_in * src, | |||||
struct inpcb *inp, int flags) | |||||
{ | |||||
struct ifnet *ifp; | |||||
struct in6_pktinfo *pktinfo; | |||||
struct in_addr ia; | |||||
if ((flags & PRUS_IPV6) == 0) | |||||
gert_greenie.muc.de: this needs to be "=="
Patch as is leads to "no UDP packet is generated at all", which is not… | |||||
return (0); | |||||
if (cm->cmsg_level != IPPROTO_IPV6) | |||||
return (0); | |||||
if (cm->cmsg_type != IPV6_2292PKTINFO && | |||||
cm->cmsg_type != IPV6_PKTINFO) | |||||
return (0); | |||||
if (cm->cmsg_len != | |||||
CMSG_LEN(sizeof(struct in6_pktinfo))) | |||||
return (EINVAL); | |||||
pktinfo = (struct in6_pktinfo *)CMSG_DATA(cm); | |||||
if (!IN6_IS_ADDR_V4MAPPED(&pktinfo->ipi6_addr) && | |||||
!IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) | |||||
return (EINVAL); | |||||
/* Validate the interface index if specified. */ | |||||
if (pktinfo->ipi6_ifindex > V_if_index) | |||||
return (ENXIO); | |||||
ifp = NULL; | |||||
if (pktinfo->ipi6_ifindex) { | |||||
ifp = ifnet_byindex(pktinfo->ipi6_ifindex); | |||||
if (ifp == NULL) | |||||
return (ENXIO); | |||||
} | |||||
if (ifp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) { | |||||
ia.s_addr = pktinfo->ipi6_addr.s6_addr32[3]; | |||||
if (in_ifhasaddr(ifp, ia) == 0) | |||||
return (EADDRNOTAVAIL); | |||||
} | |||||
bzero(src, sizeof(*src)); | |||||
src->sin_family = AF_INET; | |||||
src->sin_len = sizeof(*src); | |||||
Done Inline ActionsThis needs to be "sizeof(*src)". gert_greenie.muc.de: This needs to be "sizeof(*src)". | |||||
src->sin_port = inp->inp_lport; | |||||
src->sin_addr.s_addr = pktinfo->ipi6_addr.s6_addr32[3]; | |||||
return (0); | |||||
} | |||||
#endif | |||||
static int | |||||
udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, | udp_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr, | ||||
struct mbuf *control, struct thread *td) | struct mbuf *control, struct thread *td, int flags) | ||||
{ | { | ||||
struct udpiphdr *ui; | struct udpiphdr *ui; | ||||
int len = m->m_pkthdr.len; | int len = m->m_pkthdr.len; | ||||
struct in_addr faddr, laddr; | struct in_addr faddr, laddr; | ||||
struct cmsghdr *cm; | struct cmsghdr *cm; | ||||
struct inpcbinfo *pcbinfo; | struct inpcbinfo *pcbinfo; | ||||
struct sockaddr_in *sin, src; | struct sockaddr_in *sin, src; | ||||
struct epoch_tracker et; | struct epoch_tracker et; | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | for (; control->m_len > 0; | ||||
control->m_data += CMSG_ALIGN(cm->cmsg_len), | control->m_data += CMSG_ALIGN(cm->cmsg_len), | ||||
control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { | control->m_len -= CMSG_ALIGN(cm->cmsg_len)) { | ||||
cm = mtod(control, struct cmsghdr *); | cm = mtod(control, struct cmsghdr *); | ||||
if (control->m_len < sizeof(*cm) || cm->cmsg_len == 0 | if (control->m_len < sizeof(*cm) || cm->cmsg_len == 0 | ||||
|| cm->cmsg_len > control->m_len) { | || cm->cmsg_len > control->m_len) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
#ifdef INET6 | |||||
error = udp_v4mapped_pktinfo(cm, &src, inp, flags); | |||||
if (error != 0) | |||||
break; | |||||
#endif | |||||
if (cm->cmsg_level != IPPROTO_IP) | if (cm->cmsg_level != IPPROTO_IP) | ||||
Done Inline ActionsWould it be possible to make this code an (inlined) function like udp_set_saddr_mapped(struct cmsghdr *cm, struct sockaddr_in *sin)? melifaro: Would it be possible to make this code an (inlined) function like `udp_set_saddr_mapped(struct… | |||||
continue; | continue; | ||||
switch (cm->cmsg_type) { | switch (cm->cmsg_type) { | ||||
case IP_SENDSRCADDR: | case IP_SENDSRCADDR: | ||||
if (cm->cmsg_len != | if (cm->cmsg_len != | ||||
CMSG_LEN(sizeof(struct in_addr))) { | CMSG_LEN(sizeof(struct in_addr))) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
bzero(&src, sizeof(src)); | bzero(&src, sizeof(src)); | ||||
Done Inline Actionsthis needs to be "&&" gert_greenie.muc.de: this needs to be "&&" | |||||
src.sin_family = AF_INET; | src.sin_family = AF_INET; | ||||
src.sin_len = sizeof(src); | src.sin_len = sizeof(src); | ||||
src.sin_port = inp->inp_lport; | src.sin_port = inp->inp_lport; | ||||
src.sin_addr = | src.sin_addr = | ||||
*(struct in_addr *)CMSG_DATA(cm); | *(struct in_addr *)CMSG_DATA(cm); | ||||
break; | break; | ||||
case IP_TOS: | case IP_TOS: | ||||
if (cm->cmsg_len != CMSG_LEN(sizeof(u_char))) { | if (cm->cmsg_len != CMSG_LEN(sizeof(u_char))) { | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
} | } | ||||
tos = *(u_char *)CMSG_DATA(cm); | tos = *(u_char *)CMSG_DATA(cm); | ||||
break; | break; | ||||
case IP_FLOWID: | case IP_FLOWID: | ||||
if (cm->cmsg_len != CMSG_LEN(sizeof(uint32_t))) { | if (cm->cmsg_len != CMSG_LEN(sizeof(uint32_t))) { | ||||
error = EINVAL; | error = EINVAL; | ||||
Done Inline ActionsWould it be possible to add RFC references like RFC 3542, clause 6.5 to ease the desired functionality understanding by the readers? melifaro: Would it be possible to add RFC references like `RFC 3542, clause 6.5` to ease the desired… | |||||
Done Inline ActionsI added a reference to the main implementation. bz: I added a reference to the main implementation. | |||||
break; | break; | ||||
} | } | ||||
flowid = *(uint32_t *) CMSG_DATA(cm); | flowid = *(uint32_t *) CMSG_DATA(cm); | ||||
break; | break; | ||||
case IP_FLOWTYPE: | case IP_FLOWTYPE: | ||||
if (cm->cmsg_len != CMSG_LEN(sizeof(uint32_t))) { | if (cm->cmsg_len != CMSG_LEN(sizeof(uint32_t))) { | ||||
error = EINVAL; | error = EINVAL; | ||||
▲ Show 20 Lines • Show All 502 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, | udp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, | ||||
struct mbuf *control, struct thread *td) | struct mbuf *control, struct thread *td) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
inp = sotoinpcb(so); | inp = sotoinpcb(so); | ||||
KASSERT(inp != NULL, ("udp_send: inp == NULL")); | KASSERT(inp != NULL, ("udp_send: inp == NULL")); | ||||
return (udp_output(inp, m, addr, control, td)); | return (udp_output(inp, m, addr, control, td, flags)); | ||||
} | } | ||||
#endif /* INET */ | #endif /* INET */ | ||||
int | int | ||||
udp_shutdown(struct socket *so) | udp_shutdown(struct socket *so) | ||||
{ | { | ||||
struct inpcb *inp; | struct inpcb *inp; | ||||
Show All 27 Lines |
this needs to be "=="
Patch as is leads to "no UDP packet is generated at all", which is not what I'd expect, tbh ("wrong source address" or "EINVAL"). Not sure why.
*With* that change, I get EINVAL (again).