6 #include "qemu/osdep.h"
7 #include "qemu-common.h"
12 void udp6_input(struct mbuf
*m
)
14 Slirp
*slirp
= m
->slirp
;
15 struct ip6
*ip
, save_ip
;
17 int iphlen
= sizeof(struct ip6
);
20 struct sockaddr_in6 lhost
;
22 DEBUG_CALL("udp6_input");
23 DEBUG_ARG("m = %lx", (long)m
);
25 if (slirp
->restricted
) {
29 ip
= mtod(m
, struct ip6
*);
32 uh
= mtod(m
, struct udphdr
*);
40 len
= ntohs((uint16_t)uh
->uh_ulen
);
43 * Make mbuf data length reflect UDP length.
44 * If not enough data to reflect UDP length, drop.
46 if (ntohs(ip
->ip_pl
) != len
) {
47 if (len
> ntohs(ip
->ip_pl
)) {
50 m_adj(m
, len
- ntohs(ip
->ip_pl
));
51 ip
->ip_pl
= htons(len
);
55 * Save a copy of the IP header in case we want restore it
56 * for sending an ICMP error message in response.
60 /* Locate pcb for datagram. */
61 lhost
.sin6_family
= AF_INET6
;
62 lhost
.sin6_addr
= ip
->ip_src
;
63 lhost
.sin6_port
= uh
->uh_sport
;
66 if (ntohs(uh
->uh_dport
) == DHCPV6_SERVER_PORT
&&
67 (in6_equal(&ip
->ip_dst
, &slirp
->vhost_addr6
) ||
68 in6_dhcp_multicast(&ip
->ip_dst
))) {
71 dhcpv6_input(&lhost
, m
);
78 if (ntohs(uh
->uh_dport
) == TFTP_SERVER
&&
79 !memcmp(ip
->ip_dst
.s6_addr
, slirp
->vhost_addr6
.s6_addr
, 16)) {
82 tftp_input((struct sockaddr_storage
*)&lhost
, m
);
88 so
= solookup(&slirp
->udp_last_so
, &slirp
->udb
,
89 (struct sockaddr_storage
*) &lhost
, NULL
);
92 /* If there's no socket for this packet, create one. */
97 if (udp_attach(so
, AF_INET6
) == -1) {
98 DEBUG_MISC((dfd
, " udp6_attach errno = %d-%s\n",
99 errno
, strerror(errno
)));
105 so
->so_lfamily
= AF_INET6
;
106 so
->so_laddr6
= ip
->ip_src
;
107 so
->so_lport6
= uh
->uh_sport
;
110 so
->so_ffamily
= AF_INET6
;
111 so
->so_faddr6
= ip
->ip_dst
; /* XXX */
112 so
->so_fport6
= uh
->uh_dport
; /* XXX */
114 iphlen
+= sizeof(struct udphdr
);
119 * Now we sendto() the packet.
121 if (sosendto(so
, m
) == -1) {
125 DEBUG_MISC((dfd
, "udp tx errno = %d-%s\n", errno
, strerror(errno
)));
126 icmp6_send_error(m
, ICMP6_UNREACH
, ICMP6_UNREACH_NO_ROUTE
);
130 m_free(so
->so_m
); /* used for ICMP if error on sorecvfrom */
132 /* restore the orig mbuf packet */
143 int udp6_output(struct socket
*so
, struct mbuf
*m
,
144 struct sockaddr_in6
*saddr
, struct sockaddr_in6
*daddr
)
149 DEBUG_CALL("udp6_output");
150 DEBUG_ARG("so = %lx", (long)so
);
151 DEBUG_ARG("m = %lx", (long)m
);
153 /* adjust for header */
154 m
->m_data
-= sizeof(struct udphdr
);
155 m
->m_len
+= sizeof(struct udphdr
);
156 uh
= mtod(m
, struct udphdr
*);
157 m
->m_data
-= sizeof(struct ip6
);
158 m
->m_len
+= sizeof(struct ip6
);
159 ip
= mtod(m
, struct ip6
*);
161 /* Build IP header */
162 ip
->ip_pl
= htons(m
->m_len
- sizeof(struct ip6
));
163 ip
->ip_nh
= IPPROTO_UDP
;
164 ip
->ip_src
= saddr
->sin6_addr
;
165 ip
->ip_dst
= daddr
->sin6_addr
;
167 /* Build UDP header */
168 uh
->uh_sport
= saddr
->sin6_port
;
169 uh
->uh_dport
= daddr
->sin6_port
;
170 uh
->uh_ulen
= ip
->ip_pl
;
172 uh
->uh_sum
= ip6_cksum(m
);
173 if (uh
->uh_sum
== 0) {
177 return ip6_output(so
, m
, 0);