summaryrefslogtreecommitdiffstats
path: root/sys/netinet/udp_usrreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/udp_usrreq.c')
-rw-r--r--sys/netinet/udp_usrreq.c326
1 files changed, 265 insertions, 61 deletions
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 644cecc7f98..ff65e76a6e2 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.28 1999/11/04 11:24:24 ho Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.29 1999/12/08 06:50:20 itojun Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -84,13 +84,25 @@ extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#include <machine/stdarg.h>
#ifdef INET6
-#include <netinet6/in6.h>
-#include <netinet6/ipv6.h>
+#ifndef INET
+#include <netinet/in.h>
+#endif
+#include <netinet6/ip6.h>
#include <netinet6/in6_var.h>
-#include <netinet6/ipv6_var.h>
-#include <netinet6/ipv6_icmp.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/icmp6.h>
+#include <netinet6/ip6protosw.h>
+
+#ifndef CREATE_IPV6_MAPPED
+#define CREATE_IPV6_MAPPED(a6, a4) \
+do { \
+ bzero(&(a6), sizeof(a6)); \
+ (a6).s6_addr[10] = (a6).s6_addr[11] = 0xff; \
+ *(u_int32_t *)&(a6).s6_addr[12] = (a4); \
+} while (0)
+#endif
-extern int ipv6_defhoplmt;
+extern int ip6_defhlim;
#endif /* INET6 */
@@ -120,6 +132,29 @@ udp_init()
in_pcbinit(&udbtable, udbhashsize);
}
+#if defined(INET6) && !defined(TCP6)
+int
+udp6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp, proto;
+{
+ struct mbuf *m = *mp;
+
+#if defined(NFAITH) && 0 < NFAITH
+ if (m->m_pkthdr.rcvif) {
+ if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) {
+ /* XXX send icmp6 host/port unreach? */
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+ }
+#endif
+
+ udp_input(m, *offp, proto);
+ return IPPROTO_DONE;
+}
+#endif
+
void
#if __STDC__
udp_input(struct mbuf *m, ...)
@@ -146,7 +181,7 @@ udp_input(m, va_alist)
#endif /* INET6 */
} srcsa, dstsa;
#ifdef INET6
- struct ipv6 *ipv6;
+ struct ip6_hdr *ipv6;
struct sockaddr_in6 src_v4mapped;
#endif /* INET6 */
#ifdef IPSEC
@@ -182,7 +217,7 @@ udp_input(m, va_alist)
#ifdef INET6
case 6:
ip = NULL;
- ipv6 = mtod(m, struct ipv6 *);
+ ipv6 = mtod(m, struct ip6_hdr *);
srcsa.sa.sa_family = AF_INET6;
break;
#endif /* INET6 */
@@ -220,7 +255,7 @@ udp_input(m, va_alist)
}
#ifdef INET6
if (ipv6)
- ipv6 = mtod(m, struct ipv6 *);
+ ipv6 = mtod(m, struct ip6_hdr *);
else
#endif /* INET6 */
ip = mtod(m, struct ip *);
@@ -258,7 +293,7 @@ udp_input(m, va_alist)
/*
* In IPv6, the UDP checksum is ALWAYS used.
*/
- if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len, iphlen))) {
+ if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, iphlen, len))) {
udpstat.udps_badsum++;
goto bad;
}
@@ -304,20 +339,30 @@ udp_input(m, va_alist)
srcsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
srcsa.sin6.sin6_family = AF_INET6;
srcsa.sin6.sin6_port = uh->uh_sport;
- srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ipv6->ipv6_versfl;
- srcsa.sin6.sin6_addr = ipv6->ipv6_src;
+ srcsa.sin6.sin6_flowinfo = htonl(0x0fffffff) & ipv6->ip6_flow;
+ srcsa.sin6.sin6_addr = ipv6->ip6_src;
+ if (IN6_IS_SCOPE_LINKLOCAL(&srcsa.sin6.sin6_addr))
+ srcsa.sin6.sin6_addr.s6_addr16[1] = 0;
+ if (m->m_pkthdr.rcvif) {
+ if (IN6_IS_SCOPE_LINKLOCAL(&srcsa.sin6.sin6_addr)) {
+ srcsa.sin6.sin6_scope_id =
+ m->m_pkthdr.rcvif->if_index;
+ } else
+ srcsa.sin6.sin6_scope_id = 0;
+ } else
+ srcsa.sin6.sin6_scope_id = 0;
bzero(&dstsa, sizeof(struct sockaddr_in6));
dstsa.sin6.sin6_len = sizeof(struct sockaddr_in6);
dstsa.sin6.sin6_family = AF_INET6;
dstsa.sin6.sin6_port = uh->uh_dport;
- dstsa.sin6.sin6_addr = ipv6->ipv6_dst;
+ dstsa.sin6.sin6_addr = ipv6->ip6_dst;
break;
#endif /* INET6 */
}
#ifdef INET6
- if ((ipv6 && IN6_IS_ADDR_MULTICAST(&ipv6->ipv6_dst)) ||
+ if ((ipv6 && IN6_IS_ADDR_MULTICAST(&ipv6->ip6_dst)) ||
(ip && IN_MULTICAST(ip->ip_dst.s_addr)) ||
(ip && in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif))) {
#else /* INET6 */
@@ -361,7 +406,7 @@ udp_input(m, va_alist)
continue;
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6))
if (!IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6,
- &ipv6->ipv6_dst))
+ &ipv6->ip6_dst))
continue;
} else
#endif /* INET6 */
@@ -374,7 +419,7 @@ udp_input(m, va_alist)
if (ipv6) {
if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
if (!IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6,
- &ipv6->ipv6_src) ||
+ &ipv6->ip6_src) ||
inp->inp_fport != uh->uh_sport)
continue;
} else
@@ -391,8 +436,12 @@ udp_input(m, va_alist)
if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
#ifdef INET6
+#if 0 /*XXX*/
if (ipv6)
opts = ipv6_headertocontrol(m, iphlen, ((struct inpcb *)last->so_pcb)->inp_flags);
+#else
+ opts = NULL;
+#endif
#endif /* INET6 */
if (sbappendaddr(&last->so_rcv,
#ifdef INET6
@@ -436,9 +485,13 @@ udp_input(m, va_alist)
}
#ifdef INET6
+#if 0 /*XXX*/
if (ipv6)
opts = ipv6_headertocontrol(m, iphlen,
((struct inpcb *)last->so_pcb)->inp_flags);
+#else
+ opts = NULL;
+#endif
#endif /* INET6 */
if (sbappendaddr(&last->so_rcv,
#ifdef INET6
@@ -462,8 +515,8 @@ udp_input(m, va_alist)
*/
#ifdef INET6
if (ipv6)
- inp = in6_pcbhashlookup(&udbtable, &ipv6->ipv6_src, uh->uh_sport,
- &ipv6->ipv6_dst, uh->uh_dport);
+ inp = in6_pcbhashlookup(&udbtable, &ipv6->ip6_src, uh->uh_sport,
+ &ipv6->ip6_dst, uh->uh_dport);
else
#endif /* INET6 */
inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
@@ -473,8 +526,8 @@ udp_input(m, va_alist)
#ifdef INET6
if (ipv6) {
inp = in_pcblookup(&udbtable,
- (struct in_addr *)&(ipv6->ipv6_src),
- uh->uh_sport, (struct in_addr *)&(ipv6->ipv6_dst),
+ (struct in_addr *)&(ipv6->ip6_src),
+ uh->uh_sport, (struct in_addr *)&(ipv6->ip6_dst),
uh->uh_dport, INPLOOKUP_WILDCARD | INPLOOKUP_IPV6);
} else
#endif /* INET6 */
@@ -486,16 +539,21 @@ udp_input(m, va_alist)
udpstat.udps_noportbcast++;
goto bad;
}
- *ip = save_ip;
- HTONS(ip->ip_id);
- uh->uh_sum = savesum;
#ifdef INET6
- if (ipv6)
- ipv6_icmp_error(m, ICMPV6_UNREACH,
- ICMPV6_UNREACH_PORT,0);
- else
+ if (ipv6) {
+ icmp6_error(m, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOPORT,0);
+ } else
#endif /* INET6 */
- icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
+ {
+ *ip = save_ip;
+ HTONS(ip->ip_len);
+ HTONS(ip->ip_id);
+ HTONS(ip->ip_off);
+ uh->uh_sum = savesum;
+ icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT,
+ 0, 0);
+ }
return;
}
}
@@ -528,9 +586,13 @@ udp_input(m, va_alist)
#ifdef INET6
if (ipv6) {
+#if 0 /*XXX*/
if (inp->inp_flags & INP_IPV6)
opts = ipv6_headertocontrol(m, iphlen,
inp->inp_flags);
+#else
+ opts = NULL;
+#endif
} else
if (ip)
#endif /* INET6 */
@@ -622,6 +684,42 @@ udp_notify(inp, errno)
sowwakeup(inp->inp_socket);
}
+#if defined(INET6) && !defined(TCP6)
+void
+udp6_ctlinput(cmd, sa, d)
+ int cmd;
+ struct sockaddr *sa;
+ void *d;
+{
+ struct sockaddr_in6 sa6;
+ struct ip6_hdr *ip6;
+ struct mbuf *m;
+ int off;
+
+ if (sa == NULL)
+ return;
+ if (sa->sa_family != AF_INET6)
+ return;
+
+ /* decode parameter from icmp6. */
+ if (d != NULL) {
+ struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
+ ip6 = ip6cp->ip6c_ip6;
+ m = ip6cp->ip6c_m;
+ off = ip6cp->ip6c_off;
+ } else
+ return;
+
+ /* translate addresses into internal form */
+ sa6 = *(struct sockaddr_in6 *)sa;
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) && m && m->m_pkthdr.rcvif)
+ sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index);
+ sa = (struct sockaddr *)&sa6;
+
+ (void)udp_ctlinput(cmd, sa, (void *)ip6);
+}
+#endif
+
void *
udp_ctlinput(cmd, sa, v)
int cmd;
@@ -643,17 +741,24 @@ udp_ctlinput(cmd, sa, v)
ip = 0;
else if (errno == 0)
return NULL;
+ if (sa == NULL)
+ return NULL;
#ifdef INET6
if (sa->sa_family == AF_INET6) {
if (ip) {
- struct ipv6 *ipv6 = (struct ipv6 *)ip;
+ struct ip6_hdr *ipv6 = (struct ip6_hdr *)ip;
- uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ipv6));
+ uh = (struct udphdr *)((caddr_t)ipv6 + sizeof(struct ip6_hdr));
+#if 0 /*XXX*/
in6_pcbnotify(&udbtable, sa, uh->uh_dport,
- &(ipv6->ipv6_src), uh->uh_sport, cmd, udp_notify);
- } else
+ &(ipv6->ip6_src), uh->uh_sport, cmd, udp_notify);
+#endif
+ } else {
+#if 0 /*XXX*/
in6_pcbnotify(&udbtable, sa, 0,
(struct in6_addr *)&in6addr_any, 0, cmd, udp_notify);
+#endif
+ }
} else
#endif /* INET6 */
if (ip) {
@@ -685,6 +790,7 @@ udp_output(m, va_alist)
register struct in6_addr laddr6;
int v6packet = 0;
struct ifnet *forceif = NULL;
+ struct sockaddr_in6 *sin6 = NULL;
#endif /* INET6 */
int pcbflags = 0;
@@ -700,6 +806,10 @@ udp_output(m, va_alist)
#endif /* INET6 */
if (addr) {
+#ifdef INET6
+ sin6 = mtod(addr, struct sockaddr_in6 *);
+#endif
+
/*
* Save current PCB flags because they may change during
* temporary connection, particularly the INP_IPV6_UNDEC
@@ -710,16 +820,17 @@ udp_output(m, va_alist)
#ifdef INET6
if (inp->inp_flags & INP_IPV6)
laddr6 = inp->inp_laddr6;
- else
+ else
#endif /* INET6 */
laddr = inp->inp_laddr;
#ifdef INET6
if (((inp->inp_flags & INP_IPV6) &&
!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) ||
- (inp->inp_faddr.s_addr != INADDR_ANY)) {
+ (inp->inp_faddr.s_addr != INADDR_ANY))
#else /* INET6 */
- if (inp->inp_faddr.s_addr != INADDR_ANY) {
+ if (inp->inp_faddr.s_addr != INADDR_ANY)
#endif /* INET6 */
+ {
error = EISCONN;
goto release;
}
@@ -760,7 +871,7 @@ udp_output(m, va_alist)
m_freem(control);
M_PREPEND(m, v6packet ? (sizeof(struct udphdr) +
- sizeof(struct ipv6)) : sizeof(struct udpiphdr), M_DONTWAIT);
+ sizeof(struct ip6_hdr)) : sizeof(struct udpiphdr), M_DONTWAIT);
#else /* INET6 */
M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
#endif /* INET6 */
@@ -784,41 +895,101 @@ udp_output(m, va_alist)
*/
#ifdef INET6
if (v6packet) {
- struct ipv6 *ipv6 = mtod(m, struct ipv6 *);
+ struct ip6_hdr *ipv6 = mtod(m, struct ip6_hdr *);
struct udphdr *uh = (struct udphdr *)(mtod(m, caddr_t) +
- sizeof(struct ipv6));
- int payload = sizeof(struct ipv6);
-
- ipv6->ipv6_versfl = htonl(0x60000000) |
- (inp->inp_ipv6.ipv6_versfl & htonl(0x0fffffff));
+ sizeof(struct ip6_hdr));
+ int payload = sizeof(struct ip6_hdr);
+ struct in6_addr *faddr;
+ struct in6_addr *laddr;
+ struct ifnet *oifp = NULL;
+
+ ipv6->ip6_flow = htonl(0x60000000) |
+ (inp->inp_ipv6.ip6_flow & htonl(0x0fffffff));
- ipv6->ipv6_hoplimit = inp->inp_ipv6.ipv6_hoplimit;
- ipv6->ipv6_nexthdr = IPPROTO_UDP;
- ipv6->ipv6_src = inp->inp_laddr6;
- ipv6->ipv6_dst = inp->inp_faddr6;
- ipv6->ipv6_length = (u_short)len + sizeof(struct udphdr);
+ ipv6->ip6_nxt = IPPROTO_UDP;
+ ipv6->ip6_dst = inp->inp_faddr6;
+ /*
+ * If the scope of the destination is link-local,
+ * embed the interface
+ * index in the address.
+ *
+ * XXX advanced-api value overrides sin6_scope_id
+ */
+ faddr = &ipv6->ip6_dst;
+ if (IN6_IS_ADDR_LINKLOCAL(faddr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(faddr)) {
+ struct ip6_pktopts *optp = inp->inp_outputopts6;
+ struct in6_pktinfo *pi = NULL;
+ struct ip6_moptions *mopt = NULL;
+
+ /*
+ * XXX Boundary check is assumed to be already done in
+ * ip6_setpktoptions().
+ */
+ if (optp && (pi = optp->ip6po_pktinfo) &&
+ pi->ipi6_ifindex) {
+ faddr->s6_addr16[1] = htons(pi->ipi6_ifindex);
+ oifp = ifindex2ifnet[pi->ipi6_ifindex];
+ }
+ else if (IN6_IS_ADDR_MULTICAST(faddr) &&
+ (mopt = inp->inp_moptions6) &&
+ mopt->im6o_multicast_ifp) {
+ oifp = mopt->im6o_multicast_ifp;
+ faddr->s6_addr16[1] = oifp->if_index;
+ } else if (sin6 && sin6->sin6_scope_id) {
+ /* boundary check */
+ if (sin6->sin6_scope_id < 0
+ || if_index < sin6->sin6_scope_id) {
+ error = ENXIO; /* XXX EINVAL? */
+ goto release;
+ }
+ /* XXX */
+ faddr->s6_addr16[1] =
+ htons(sin6->sin6_scope_id & 0xffff);
+ }
+ }
+ ipv6->ip6_hlim = in6_selecthlim(inp, oifp);
+ if (sin6) { /*XXX*/
+ laddr = in6_selectsrc(sin6, inp->inp_outputopts6,
+ inp->inp_moptions6,
+ &inp->inp_route6,
+ &inp->inp_laddr6, &error);
+ if (laddr == NULL) {
+ if (error == 0)
+ error = EADDRNOTAVAIL;
+ goto release;
+ }
+ } else
+ laddr = &inp->inp_laddr6;
+
+ ipv6->ip6_src = *laddr;
+
+ ipv6->ip6_plen = (u_short)len + sizeof(struct udphdr);
uh->uh_sport = inp->inp_lport;
uh->uh_dport = inp->inp_fport;
- uh->uh_ulen = htons(ipv6->ipv6_length);
+ uh->uh_ulen = htons(ipv6->ip6_plen);
uh->uh_sum = 0;
- if (control)
+ if (control) {
+#if 0 /*XXX*/
if ((error = ipv6_controltoheader(&m, control,
&forceif, &payload)))
goto release;
+#endif
+ }
/*
* Always calculate udp checksum for IPv6 datagrams
*/
- if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP, len +
- sizeof(struct udphdr), payload)))
+ if (!(uh->uh_sum = in6_cksum(m, IPPROTO_UDP,
+ payload, len + sizeof(struct udphdr))))
uh->uh_sum = 0xffff;
- error = ipv6_output(m, &inp->inp_route6,
+ error = ip6_output(m, NULL, &inp->inp_route6,
inp->inp_socket->so_options & SO_DONTROUTE,
(inp->inp_flags & INP_IPV6_MCAST)?inp->inp_moptions6:NULL,
- forceif, inp->inp_socket);
+ &forceif);
} else
#endif /* INET6 */
{
@@ -901,6 +1072,19 @@ u_int udp_sendspace = 9216; /* really max datagram size */
u_int udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in));
/* 40 1K datagrams */
+#if defined(INET6) && !defined(TCP6)
+/*ARGSUSED*/
+int
+udp6_usrreq(so, req, m, addr, control, p)
+ struct socket *so;
+ int req;
+ struct mbuf *m, *addr, *control;
+ struct proc *p;
+{
+ return udp_usrreq(so, req, m, addr, control);
+}
+#endif
+
/*ARGSUSED*/
int
udp_usrreq(so, req, m, addr, control)
@@ -947,8 +1131,8 @@ udp_usrreq(so, req, m, addr, control)
break;
#ifdef INET6
if (((struct inpcb *)so->so_pcb)->inp_flags & INP_IPV6)
- ((struct inpcb *) so->so_pcb)->inp_ipv6.ipv6_hoplimit =
- ipv6_defhoplmt;
+ ((struct inpcb *) so->so_pcb)->inp_ipv6.ip6_hlim =
+ ip6_defhlim;
else
#endif /* INET6 */
((struct inpcb *) so->so_pcb)->inp_ip.ip_ttl = ip_defttl;
@@ -960,7 +1144,12 @@ udp_usrreq(so, req, m, addr, control)
case PRU_BIND:
s = splsoftnet();
- error = in_pcbbind(inp, addr);
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ error = in6_pcbbind(inp, addr);
+ else
+#endif
+ error = in_pcbbind(inp, addr);
splx(s);
break;
@@ -975,16 +1164,21 @@ udp_usrreq(so, req, m, addr, control)
error = EISCONN;
break;
}
+ s = splsoftnet();
+ error = in6_pcbconnect(inp, addr);
+ splx(s);
} else
#endif /* INET6 */
+ {
if (inp->inp_faddr.s_addr != INADDR_ANY) {
error = EISCONN;
break;
}
+ s = splsoftnet();
+ error = in_pcbconnect(inp, addr);
+ splx(s);
+ }
- s = splsoftnet();
- error = in_pcbconnect(inp, addr);
- splx(s);
if (error == 0)
soisconnected(so);
break;
@@ -1042,11 +1236,21 @@ udp_usrreq(so, req, m, addr, control)
break;
case PRU_SOCKADDR:
- in_setsockaddr(inp, addr);
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ in6_setsockaddr(inp, addr);
+ else
+#endif /* INET6 */
+ in_setsockaddr(inp, addr);
break;
case PRU_PEERADDR:
- in_setpeeraddr(inp, addr);
+#ifdef INET6
+ if (inp->inp_flags & INP_IPV6)
+ in6_setpeeraddr(inp, addr);
+ else
+#endif /* INET6 */
+ in_setpeeraddr(inp, addr);
break;
case PRU_SENSE: