Annotation of qemu/slirp/udp.c, revision 1.1.1.9
1.1 root 1: /*
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.
1.1.1.6 root 13: * 3. Neither the name of the University nor the names of its contributors
1.1 root 14: * 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.
1.1.1.5 root 36: *
37: * Please read the file COPYRIGHT for the
1.1 root 38: * terms and conditions of the copyright.
39: */
40:
41: #include <slirp.h>
42: #include "ip_icmp.h"
43:
1.1.1.9 ! root 44: static uint8_t udp_tos(struct socket *so);
1.1.1.5 root 45:
1.1 root 46: void
1.1.1.7 root 47: udp_init(Slirp *slirp)
1.1 root 48: {
1.1.1.7 root 49: slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
50: slirp->udp_last_so = &slirp->udb;
1.1 root 51: }
1.1.1.5 root 52: /* m->m_data points at ip packet header
53: * m->m_len length ip packet
1.1 root 54: * ip->ip_len length data (IPDU)
55: */
56: void
1.1.1.7 root 57: udp_input(register struct mbuf *m, int iphlen)
1.1 root 58: {
1.1.1.7 root 59: Slirp *slirp = m->slirp;
1.1 root 60: register struct ip *ip;
61: register struct udphdr *uh;
62: int len;
1.1.1.5 root 63: struct ip save_ip;
1.1 root 64: struct socket *so;
1.1.1.5 root 65:
1.1 root 66: DEBUG_CALL("udp_input");
67: DEBUG_ARG("m = %lx", (long)m);
68: DEBUG_ARG("iphlen = %d", iphlen);
1.1.1.5 root 69:
1.1 root 70: /*
71: * Strip IP options, if any; should skip this,
72: * make available to user, and use on returned packets,
73: * but we don't yet have a way to check the checksum
74: * with options still present.
75: */
76: if(iphlen > sizeof(struct ip)) {
77: ip_stripoptions(m, (struct mbuf *)0);
78: iphlen = sizeof(struct ip);
79: }
80:
81: /*
82: * Get IP and UDP header together in first mbuf.
83: */
84: ip = mtod(m, struct ip *);
85: uh = (struct udphdr *)((caddr_t)ip + iphlen);
86:
87: /*
88: * Make mbuf data length reflect UDP length.
89: * If not enough data to reflect UDP length, drop.
90: */
1.1.1.9 ! root 91: len = ntohs((uint16_t)uh->uh_ulen);
1.1 root 92:
93: if (ip->ip_len != len) {
94: if (len > ip->ip_len) {
95: goto bad;
96: }
97: m_adj(m, len - ip->ip_len);
98: ip->ip_len = len;
99: }
1.1.1.5 root 100:
1.1 root 101: /*
102: * Save a copy of the IP header in case we want restore it
103: * for sending an ICMP error message in response.
104: */
1.1.1.5 root 105: save_ip = *ip;
1.1 root 106: save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
107:
108: /*
109: * Checksum extended UDP header and data.
110: */
1.1.1.7 root 111: if (uh->uh_sum) {
1.1.1.6 root 112: memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
1.1 root 113: ((struct ipovly *)ip)->ih_x1 = 0;
114: ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
115: if(cksum(m, len + sizeof(struct ip))) {
116: goto bad;
117: }
118: }
119:
120: /*
121: * handle DHCP/BOOTP
122: */
123: if (ntohs(uh->uh_dport) == BOOTP_SERVER) {
124: bootp_input(m);
125: goto bad;
126: }
127:
1.1.1.7 root 128: if (slirp->restricted) {
1.1.1.6 root 129: goto bad;
1.1.1.7 root 130: }
1.1.1.6 root 131:
1.1 root 132: /*
133: * handle TFTP
134: */
135: if (ntohs(uh->uh_dport) == TFTP_SERVER) {
136: tftp_input(m);
137: goto bad;
138: }
139:
140: /*
141: * Locate pcb for datagram.
142: */
1.1.1.7 root 143: so = slirp->udp_last_so;
1.1 root 144: if (so->so_lport != uh->uh_sport ||
145: so->so_laddr.s_addr != ip->ip_src.s_addr) {
146: struct socket *tmp;
1.1.1.5 root 147:
1.1.1.7 root 148: for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
149: tmp = tmp->so_next) {
1.1 root 150: if (tmp->so_lport == uh->uh_sport &&
151: tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
152: so = tmp;
153: break;
154: }
155: }
1.1.1.7 root 156: if (tmp == &slirp->udb) {
1.1 root 157: so = NULL;
158: } else {
1.1.1.7 root 159: slirp->udp_last_so = so;
1.1 root 160: }
161: }
1.1.1.5 root 162:
1.1 root 163: if (so == NULL) {
164: /*
165: * If there's no socket for this packet,
166: * create one
167: */
1.1.1.7 root 168: so = socreate(slirp);
169: if (!so) {
170: goto bad;
171: }
1.1 root 172: if(udp_attach(so) == -1) {
1.1.1.5 root 173: DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
1.1 root 174: errno,strerror(errno)));
175: sofree(so);
176: goto bad;
177: }
1.1.1.5 root 178:
1.1 root 179: /*
180: * Setup fields
181: */
182: so->so_laddr = ip->ip_src;
183: so->so_lport = uh->uh_sport;
1.1.1.5 root 184:
1.1 root 185: if ((so->so_iptos = udp_tos(so)) == 0)
186: so->so_iptos = ip->ip_tos;
1.1.1.5 root 187:
1.1 root 188: /*
189: * XXXXX Here, check if it's in udpexec_list,
190: * and if it is, do the fork_exec() etc.
191: */
192: }
193:
1.1.1.4 root 194: so->so_faddr = ip->ip_dst; /* XXX */
195: so->so_fport = uh->uh_dport; /* XXX */
196:
1.1 root 197: iphlen += sizeof(struct udphdr);
198: m->m_len -= iphlen;
199: m->m_data += iphlen;
200:
201: /*
202: * Now we sendto() the packet.
203: */
204: if(sosendto(so,m) == -1) {
205: m->m_len += iphlen;
206: m->m_data -= iphlen;
207: *ip=save_ip;
208: DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
1.1.1.5 root 209: icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
1.1 root 210: }
211:
212: m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
213:
214: /* restore the orig mbuf packet */
215: m->m_len += iphlen;
216: m->m_data -= iphlen;
217: *ip=save_ip;
218: so->so_m=m; /* ICMP backup */
219:
220: return;
221: bad:
222: m_freem(m);
223: return;
224: }
225:
1.1.1.5 root 226: int udp_output2(struct socket *so, struct mbuf *m,
1.1 root 227: struct sockaddr_in *saddr, struct sockaddr_in *daddr,
228: int iptos)
229: {
230: register struct udpiphdr *ui;
231: int error = 0;
232:
233: DEBUG_CALL("udp_output");
234: DEBUG_ARG("so = %lx", (long)so);
235: DEBUG_ARG("m = %lx", (long)m);
236: DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
237: DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
238:
239: /*
240: * Adjust for header
241: */
242: m->m_data -= sizeof(struct udpiphdr);
243: m->m_len += sizeof(struct udpiphdr);
1.1.1.5 root 244:
1.1 root 245: /*
246: * Fill in mbuf with extended UDP header
247: * and addresses and length put into network format.
248: */
249: ui = mtod(m, struct udpiphdr *);
1.1.1.6 root 250: memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
1.1 root 251: ui->ui_x1 = 0;
252: ui->ui_pr = IPPROTO_UDP;
1.1.1.7 root 253: ui->ui_len = htons(m->m_len - sizeof(struct ip));
1.1 root 254: /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
255: ui->ui_src = saddr->sin_addr;
256: ui->ui_dst = daddr->sin_addr;
257: ui->ui_sport = saddr->sin_port;
258: ui->ui_dport = daddr->sin_port;
259: ui->ui_ulen = ui->ui_len;
260:
261: /*
262: * Stuff checksum and output datagram.
263: */
264: ui->ui_sum = 0;
1.1.1.7 root 265: if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
1.1 root 266: ui->ui_sum = 0xffff;
267: ((struct ip *)ui)->ip_len = m->m_len;
268:
1.1.1.5 root 269: ((struct ip *)ui)->ip_ttl = IPDEFTTL;
1.1 root 270: ((struct ip *)ui)->ip_tos = iptos;
1.1.1.5 root 271:
1.1 root 272: error = ip_output(so, m);
1.1.1.5 root 273:
1.1 root 274: return (error);
275: }
276:
1.1.1.5 root 277: int udp_output(struct socket *so, struct mbuf *m,
1.1 root 278: struct sockaddr_in *addr)
279:
280: {
1.1.1.7 root 281: Slirp *slirp = so->slirp;
1.1 root 282: struct sockaddr_in saddr, daddr;
283:
284: saddr = *addr;
1.1.1.7 root 285: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
286: slirp->vnetwork_addr.s_addr) {
287: uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
288:
289: if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
290: saddr.sin_addr = slirp->vhost_addr;
291: } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
292: so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
293: saddr.sin_addr = so->so_faddr;
294: }
1.1.1.3 root 295: }
1.1 root 296: daddr.sin_addr = so->so_laddr;
297: daddr.sin_port = so->so_lport;
1.1.1.5 root 298:
1.1 root 299: return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
300: }
301:
302: int
1.1.1.7 root 303: udp_attach(struct socket *so)
1.1 root 304: {
1.1.1.8 root 305: if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
306: so->so_expire = curtime + SO_EXPIRE;
307: insque(so, &so->slirp->udb);
1.1 root 308: }
309: return(so->s);
310: }
311:
312: void
1.1.1.7 root 313: udp_detach(struct socket *so)
1.1 root 314: {
315: closesocket(so->s);
316: sofree(so);
317: }
318:
1.1.1.5 root 319: static const struct tos_t udptos[] = {
1.1 root 320: {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
321: {0, 0, 0, 0}
322: };
323:
1.1.1.9 ! root 324: static uint8_t
1.1.1.5 root 325: udp_tos(struct socket *so)
1.1 root 326: {
327: int i = 0;
1.1.1.5 root 328:
1.1 root 329: while(udptos[i].tos) {
330: if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
331: (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
332: so->so_emu = udptos[i].emu;
333: return udptos[i].tos;
334: }
335: i++;
336: }
1.1.1.5 root 337:
1.1 root 338: return 0;
339: }
340:
341: struct socket *
1.1.1.9 ! root 342: udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
1.1.1.7 root 343: u_int lport, int flags)
1.1 root 344: {
345: struct sockaddr_in addr;
346: struct socket *so;
1.1.1.6 root 347: socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
1.1.1.5 root 348:
1.1.1.7 root 349: so = socreate(slirp);
350: if (!so) {
351: return NULL;
1.1 root 352: }
1.1.1.8 root 353: so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
1.1 root 354: so->so_expire = curtime + SO_EXPIRE;
1.1.1.7 root 355: insque(so, &slirp->udb);
1.1 root 356:
357: addr.sin_family = AF_INET;
1.1.1.7 root 358: addr.sin_addr.s_addr = haddr;
359: addr.sin_port = hport;
1.1 root 360:
361: if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
362: udp_detach(so);
363: return NULL;
364: }
365: setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
1.1.1.5 root 366:
1.1 root 367: getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
368: so->so_fport = addr.sin_port;
1.1.1.7 root 369: if (addr.sin_addr.s_addr == 0 ||
370: addr.sin_addr.s_addr == loopback_addr.s_addr) {
371: so->so_faddr = slirp->vhost_addr;
372: } else {
1.1 root 373: so->so_faddr = addr.sin_addr;
1.1.1.7 root 374: }
1.1 root 375: so->so_lport = lport;
376: so->so_laddr.s_addr = laddr;
377: if (flags != SS_FACCEPTONCE)
378: so->so_expire = 0;
1.1.1.5 root 379:
1.1.1.7 root 380: so->so_state &= SS_PERSISTENT_MASK;
381: so->so_state |= SS_ISFCONNECTED | flags;
1.1.1.5 root 382:
1.1 root 383: return so;
384: }
unix.superglobalmegacorp.com