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.
13: * 3. Neither the name of the University nor the names of its contributors
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.
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:
44: static u_int8_t udp_tos(struct socket *so);
45:
46: void
47: udp_init(Slirp *slirp)
48: {
49: slirp->udb.so_next = slirp->udb.so_prev = &slirp->udb;
50: slirp->udp_last_so = &slirp->udb;
51: }
52: /* m->m_data points at ip packet header
53: * m->m_len length ip packet
54: * ip->ip_len length data (IPDU)
55: */
56: void
57: udp_input(register struct mbuf *m, int iphlen)
58: {
59: Slirp *slirp = m->slirp;
60: register struct ip *ip;
61: register struct udphdr *uh;
62: int len;
63: struct ip save_ip;
64: struct socket *so;
65:
66: DEBUG_CALL("udp_input");
67: DEBUG_ARG("m = %lx", (long)m);
68: DEBUG_ARG("iphlen = %d", iphlen);
69:
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: */
91: len = ntohs((u_int16_t)uh->uh_ulen);
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: }
100:
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: */
105: save_ip = *ip;
106: save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
107:
108: /*
109: * Checksum extended UDP header and data.
110: */
111: if (uh->uh_sum) {
112: memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr));
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:
128: if (slirp->restricted) {
129: goto bad;
130: }
131:
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: */
143: so = slirp->udp_last_so;
144: if (so->so_lport != uh->uh_sport ||
145: so->so_laddr.s_addr != ip->ip_src.s_addr) {
146: struct socket *tmp;
147:
148: for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
149: tmp = tmp->so_next) {
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: }
156: if (tmp == &slirp->udb) {
157: so = NULL;
158: } else {
159: slirp->udp_last_so = so;
160: }
161: }
162:
163: if (so == NULL) {
164: /*
165: * If there's no socket for this packet,
166: * create one
167: */
168: so = socreate(slirp);
169: if (!so) {
170: goto bad;
171: }
172: if(udp_attach(so) == -1) {
173: DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
174: errno,strerror(errno)));
175: sofree(so);
176: goto bad;
177: }
178:
179: /*
180: * Setup fields
181: */
182: so->so_laddr = ip->ip_src;
183: so->so_lport = uh->uh_sport;
184:
185: if ((so->so_iptos = udp_tos(so)) == 0)
186: so->so_iptos = ip->ip_tos;
187:
188: /*
189: * XXXXX Here, check if it's in udpexec_list,
190: * and if it is, do the fork_exec() etc.
191: */
192: }
193:
194: so->so_faddr = ip->ip_dst; /* XXX */
195: so->so_fport = uh->uh_dport; /* XXX */
196:
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)));
209: icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
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:
226: int udp_output2(struct socket *so, struct mbuf *m,
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);
244:
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 *);
250: memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
251: ui->ui_x1 = 0;
252: ui->ui_pr = IPPROTO_UDP;
253: ui->ui_len = htons(m->m_len - sizeof(struct ip));
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;
265: if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
266: ui->ui_sum = 0xffff;
267: ((struct ip *)ui)->ip_len = m->m_len;
268:
269: ((struct ip *)ui)->ip_ttl = IPDEFTTL;
270: ((struct ip *)ui)->ip_tos = iptos;
271:
272: error = ip_output(so, m);
273:
274: return (error);
275: }
276:
277: int udp_output(struct socket *so, struct mbuf *m,
278: struct sockaddr_in *addr)
279:
280: {
281: Slirp *slirp = so->slirp;
282: struct sockaddr_in saddr, daddr;
283:
284: saddr = *addr;
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: }
295: }
296: daddr.sin_addr = so->so_laddr;
297: daddr.sin_port = so->so_lport;
298:
299: return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
300: }
301:
302: int
303: udp_attach(struct socket *so)
304: {
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);
308: }
309: return(so->s);
310: }
311:
312: void
313: udp_detach(struct socket *so)
314: {
315: closesocket(so->s);
316: sofree(so);
317: }
318:
319: static const struct tos_t udptos[] = {
320: {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */
321: {0, 0, 0, 0}
322: };
323:
324: static u_int8_t
325: udp_tos(struct socket *so)
326: {
327: int i = 0;
328:
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: }
337:
338: return 0;
339: }
340:
341: struct socket *
342: udp_listen(Slirp *slirp, u_int32_t haddr, u_int hport, u_int32_t laddr,
343: u_int lport, int flags)
344: {
345: struct sockaddr_in addr;
346: struct socket *so;
347: socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
348:
349: so = socreate(slirp);
350: if (!so) {
351: return NULL;
352: }
353: so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
354: so->so_expire = curtime + SO_EXPIRE;
355: insque(so, &slirp->udb);
356:
357: addr.sin_family = AF_INET;
358: addr.sin_addr.s_addr = haddr;
359: addr.sin_port = hport;
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));
366:
367: getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
368: so->so_fport = addr.sin_port;
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 {
373: so->so_faddr = addr.sin_addr;
374: }
375: so->so_lport = lport;
376: so->so_laddr.s_addr = laddr;
377: if (flags != SS_FACCEPTONCE)
378: so->so_expire = 0;
379:
380: so->so_state &= SS_PERSISTENT_MASK;
381: so->so_state |= SS_ISFCONNECTED | flags;
382:
383: return so;
384: }
unix.superglobalmegacorp.com