Statistics
| Branch: | Revision:

root / slirp / udp.c @ b6dce92e

History | View | Annotate | Download (9.5 kB)

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 uint8_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((uint16_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 uint8_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, uint32_t haddr, u_int hport, uint32_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
}