blob: 90915050e99a854f4745be8266dd07c9d420e1bb [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070013 * 3. Neither the name of the University nor the names of its contributors
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080014 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94
30 * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp
31 */
32
33/*
34 * Changes and additions relating to SLiRP
35 * Copyright (c) 1995 Danny Gasparovski.
36 *
37 * Please read the file COPYRIGHT for the
38 * terms and conditions of the copyright.
39 */
40
41#include <slirp.h>
42#include "ip_icmp.h"
43#define SLIRP_COMPILATION 1
44#include "sockets.h"
45
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070046#ifdef LOG_ENABLED
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080047struct udpstat udpstat;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070048#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080049
50struct socket udb;
51
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070052static u_int8_t udp_tos(struct socket *so);
53static void udp_emu(struct socket *so, struct mbuf *m);
54
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080055/*
56 * UDP protocol implementation.
57 * Per RFC 768, August, 1980.
58 */
59#ifndef COMPAT_42
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070060#define UDPCKSUM 1
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080061#else
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070062#define UDPCKSUM 0 /* XXX */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080063#endif
64
65struct socket *udp_last_so = &udb;
66
67void
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070068udp_init(void)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080069{
70 udb.so_next = udb.so_prev = &udb;
71}
72/* m->m_data points at ip packet header
73 * m->m_len length ip packet
74 * ip->ip_len length data (IPDU)
75 */
76void
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070077udp_input(register struct mbuf *m, int iphlen)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080078{
79 register struct ip *ip;
80 register struct udphdr *uh;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070081/* struct mbuf *opts = 0;*/
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080082 int len;
83 struct ip save_ip;
84 struct socket *so;
85
86 DEBUG_CALL("udp_input");
87 DEBUG_ARG("m = %lx", (long)m);
88 DEBUG_ARG("iphlen = %d", iphlen);
89
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070090 STAT(udpstat.udps_ipackets++);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080091
92 /*
93 * Strip IP options, if any; should skip this,
94 * make available to user, and use on returned packets,
95 * but we don't yet have a way to check the checksum
96 * with options still present.
97 */
98 if(iphlen > sizeof(struct ip)) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070099 ip_stripoptions(m, (struct mbuf *)0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800100 iphlen = sizeof(struct ip);
101 }
102
103 /*
104 * Get IP and UDP header together in first mbuf.
105 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700106 ip = mtod(m, struct ip *);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800107 uh = (struct udphdr *)((caddr_t)ip + iphlen);
108
109 /*
110 * Make mbuf data length reflect UDP length.
111 * If not enough data to reflect UDP length, drop.
112 */
113 len = ntohs((u_int16_t)uh->uh_ulen);
114
115 if (ip->ip_len != len) {
116 if (len > ip->ip_len) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700117 STAT(udpstat.udps_badlen++);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800118 goto bad;
119 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700120 m_adj(m, len - ip->ip_len);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800121 ip->ip_len = len;
122 }
123
124 /*
125 * Save a copy of the IP header in case we want restore it
126 * for sending an ICMP error message in response.
127 */
128 save_ip = *ip;
129 save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
130
131 /*
132 * Checksum extended UDP header and data.
133 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700134 if (UDPCKSUM && uh->uh_sum) {
135 memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800136 ((struct ipovly *)ip)->ih_x1 = 0;
137 ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
138 /* keep uh_sum for ICMP reply
139 * uh->uh_sum = cksum(m, len + sizeof (struct ip));
140 * if (uh->uh_sum) {
141 */
142 if(cksum(m, len + sizeof(struct ip))) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700143 STAT(udpstat.udps_badsum++);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800144 goto bad;
145 }
146 }
147
148 /*
149 * handle DHCP/BOOTP
150 */
151 if (port_geth(uh->uh_dport) == BOOTP_SERVER) {
152 bootp_input(m);
153 goto bad;
154 }
155
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700156 if (slirp_restrict)
157 goto bad;
158
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800159 /*
160 * handle TFTP
161 */
162 if (port_geth(uh->uh_dport) == TFTP_SERVER) {
163 tftp_input(m);
164 goto bad;
165 }
166
167 /*
168 * Locate pcb for datagram.
169 */
170 so = udp_last_so;
171 if (so->so_laddr_port != port_geth(uh->uh_sport) ||
172 so->so_laddr_ip != ip_geth(ip->ip_src)) {
173 struct socket *tmp;
174
175 for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
176 if (tmp->so_laddr_port == port_geth(uh->uh_sport) &&
177 tmp->so_laddr_ip == ip_geth(ip->ip_src)) {
178 tmp->so_faddr_ip = ip_geth(ip->ip_dst);
179 tmp->so_faddr_port = port_geth(uh->uh_dport);
180 so = tmp;
181 break;
182 }
183 }
184 if (tmp == &udb) {
185 so = NULL;
186 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700187 STAT(udpstat.udpps_pcbcachemiss++);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800188 udp_last_so = so;
189 }
190 }
191
192 if (so == NULL) {
193 /*
194 * If there's no socket for this packet,
195 * create one
196 */
197 if ((so = socreate()) == NULL) goto bad;
198 if(udp_attach(so) == -1) {
199 DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
200 errno,errno_str));
201 sofree(so);
202 goto bad;
203 }
204
205 /*
206 * Setup fields
207 */
208 /* udp_last_so = so; */
209 so->so_laddr_ip = ip_geth(ip->ip_src);
210 so->so_laddr_port = port_geth(uh->uh_sport);
211
212 if ((so->so_iptos = udp_tos(so)) == 0)
213 so->so_iptos = ip->ip_tos;
214
215 /*
216 * XXXXX Here, check if it's in udpexec_list,
217 * and if it is, do the fork_exec() etc.
218 */
219 }
220
221 so->so_faddr_ip = ip_geth(ip->ip_dst); /* XXX */
222 so->so_faddr_port = port_geth(uh->uh_dport); /* XXX */
223
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700224 iphlen += sizeof(struct udphdr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800225 m->m_len -= iphlen;
226 m->m_data += iphlen;
227
228 /*
229 * Now we sendto() the packet.
230 */
231 if (so->so_emu)
232 udp_emu(so, m);
233
234 if(sosendto(so,m) == -1) {
235 m->m_len += iphlen;
236 m->m_data -= iphlen;
237 *ip=save_ip;
238 DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno, errno_str));
239 icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,errno_str);
240 }
241
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700242 m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800243
244 /* restore the orig mbuf packet */
245 m->m_len += iphlen;
246 m->m_data -= iphlen;
247 *ip=save_ip;
248 so->so_m=m; /* ICMP backup */
249
250 return;
251bad:
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700252 m_freem(m);
253 /* if (opts) m_freem(opts); */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800254 return;
255}
256
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700257int udp_output2_(struct socket *so, struct mbuf *m,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800258 const SockAddress* saddr,
259 const SockAddress* daddr,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700260 int iptos)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800261{
262 register struct udpiphdr *ui;
263 uint32_t saddr_ip = sock_address_get_ip(saddr);
264 uint32_t daddr_ip = sock_address_get_ip(daddr);
265 int saddr_port = sock_address_get_port(saddr);
266 int daddr_port = sock_address_get_port(daddr);
267 int error = 0;
268
269 DEBUG_CALL("udp_output");
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700270 DEBUG_ARG("so = %lx", (long)so);
271 DEBUG_ARG("m = %lx", (long)m);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800272 DEBUG_ARG("saddr = %lx", (long) saddr_ip);
273 DEBUG_ARG("daddr = %lx", (long) daddr_ip);
274
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700275 /*
276 * Adjust for header
277 */
278 m->m_data -= sizeof(struct udpiphdr);
279 m->m_len += sizeof(struct udpiphdr);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800280
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700281 /*
282 * Fill in mbuf with extended UDP header
283 * and addresses and length put into network format.
284 */
285 ui = mtod(m, struct udpiphdr *);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800286 memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700287 ui->ui_x1 = 0;
288 ui->ui_pr = IPPROTO_UDP;
289 ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */
290 /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800291 ui->ui_src = ip_seth(saddr_ip);
292 ui->ui_dst = ip_seth(daddr_ip);
293 ui->ui_sport = port_seth(saddr_port);
294 ui->ui_dport = port_seth(daddr_port);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700295 ui->ui_ulen = ui->ui_len;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800296
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700297 /*
298 * Stuff checksum and output datagram.
299 */
300 ui->ui_sum = 0;
301 if (UDPCKSUM) {
302 if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0)
303 ui->ui_sum = 0xffff;
304 }
305 ((struct ip *)ui)->ip_len = m->m_len;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800306
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700307 ((struct ip *)ui)->ip_ttl = IPDEFTTL;
308 ((struct ip *)ui)->ip_tos = iptos;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800309
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700310 STAT(udpstat.udps_opackets++);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800311
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700312 error = ip_output(so, m);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800313
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700314 return (error);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800315}
316
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700317int udp_output_(struct socket *so, struct mbuf *m,
318 SockAddress* from)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800319{
320 SockAddress saddr, daddr;
321 uint32_t saddr_ip;
322 uint16_t saddr_port;
323
324 saddr_ip = sock_address_get_ip(from);
325 saddr_port = sock_address_get_port(from);
326
327 if ((so->so_faddr_ip & 0xffffff00) == special_addr_ip) {
328 saddr_ip = so->so_faddr_ip;
329 if ((so->so_faddr_ip & 0x000000ff) == 0xff)
330 saddr_ip = alias_addr_ip;
331 }
332
333 sock_address_init_inet( &saddr, saddr_ip, saddr_port );
334 sock_address_init_inet( &daddr, so->so_laddr_ip, so->so_laddr_port );
335
336 return udp_output2_(so, m, &saddr, &daddr, so->so_iptos);
337}
338
339int
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700340udp_attach(struct socket *so)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800341{
342 so->s = socket_anyaddr_server( 0, SOCKET_DGRAM );
343 if (so->s != -1) {
344 /* success, insert in queue */
345 so->so_expire = curtime + SO_EXPIRE;
346 insque(so,&udb);
347 }
348 return(so->s);
349}
350
351void
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700352udp_detach(struct socket *so)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800353{
354 socket_close(so->s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700355 /* if (so->so_m) m_free(so->so_m); done by sofree */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800356
357 sofree(so);
358}
359
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700360static const struct tos_t udptos[] = {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800361 {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
362 {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */
363 {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */
364 {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */
365 {0, 0, 0, 0}
366};
367
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700368static u_int8_t
369udp_tos(struct socket *so)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800370{
371 int i = 0;
372
373 while(udptos[i].tos) {
374 if ((udptos[i].fport && so->so_faddr_port == udptos[i].fport) ||
375 (udptos[i].lport && so->so_laddr_port == udptos[i].lport)) {
376 so->so_emu = udptos[i].emu;
377 return udptos[i].tos;
378 }
379 i++;
380 }
381
382 return 0;
383}
384
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700385
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800386/*
387 * Here, talk/ytalk/ntalk requests must be emulated
388 */
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700389static void
390udp_emu(struct socket *so, struct mbuf *m)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800391{
392 SockAddress sockaddr;
393
394struct cu_header {
395 uint16_t d_family; // destination family
396 uint16_t d_port; // destination port
397 uint32_t d_addr; // destination address
398 uint16_t s_family; // source family
399 uint16_t s_port; // source port
400 uint32_t so_addr; // source address
401 uint32_t seqn; // sequence number
402 uint16_t message; // message
403 uint16_t data_type; // data type
404 uint16_t pkt_len; // packet length
405} *cu_head;
406
407 switch(so->so_emu) {
408
409 case EMU_CUSEEME:
410
411 /*
412 * Cu-SeeMe emulation.
413 * Hopefully the packet is more that 16 bytes long. We don't
414 * do any other tests, just replace the address and port
415 * fields.
416 */
417 if (m->m_len >= sizeof (*cu_head)) {
418 if (socket_get_address(so->s, &sockaddr) < 0)
419 return;
420
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700421 cu_head = mtod(m, struct cu_header *);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800422 cu_head->s_port = htons( sock_address_get_port(&sockaddr));
423 cu_head->so_addr = htonl( sock_address_get_ip(&sockaddr));
424 }
425
426 return;
427 }
428}
429
430struct socket *
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700431udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800432{
433 struct socket *so;
434 SockAddress addr;
435 uint32_t addr_ip;
436
437 if ((so = socreate()) == NULL) {
438 free(so);
439 return NULL;
440 }
441 so->s = socket_anyaddr_server( port, SOCKET_DGRAM );
442 so->so_expire = curtime + SO_EXPIRE;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700443 so->so_haddr_port = port;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800444 insque(so,&udb);
445
446 if (so->s < 0) {
447 udp_detach(so);
448 return NULL;
449 }
450
451 socket_get_address(so->s, &addr);
452
453 so->so_faddr_port = sock_address_get_port(&addr);
454 addr_ip = sock_address_get_ip(&addr);
455
456 if (addr_ip == 0 || addr_ip == loopback_addr_ip)
457 so->so_faddr_ip = alias_addr_ip;
458 else
459 so->so_faddr_ip = addr_ip;
460
461 so->so_laddr_port = lport;
462 so->so_laddr_ip = laddr;
463 if (flags != SS_FACCEPTONCE)
464 so->so_expire = 0;
465
466 so->so_state = SS_ISFCONNECTED;
467
468 return so;
469}
470
471int udp_unlisten (u_int port)
472{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700473 return slirp_unredir(1, port);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800474}