Statistics
| Branch: | Revision:

root / slirp / udp.c @ 90d7416a

History | View | Annotate | Download (9.7 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
            (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
125
             ip->ip_dst.s_addr == 0xffffffff)) {
126
                bootp_input(m);
127
                goto bad;
128
            }
129

    
130
        /*
131
         *  handle TFTP
132
         */
133
        if (ntohs(uh->uh_dport) == TFTP_SERVER &&
134
            ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
135
            tftp_input(m);
136
            goto bad;
137
        }
138

    
139
        if (slirp->restricted) {
140
            goto bad;
141
        }
142

    
143
        /*
144
         * Locate pcb for datagram.
145
         */
146
        so = slirp->udp_last_so;
147
        if (so->so_lport != uh->uh_sport ||
148
            so->so_laddr.s_addr != ip->ip_src.s_addr) {
149
                struct socket *tmp;
150

    
151
                for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
152
                     tmp = tmp->so_next) {
153
                        if (tmp->so_lport == uh->uh_sport &&
154
                            tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
155
                                so = tmp;
156
                                break;
157
                        }
158
                }
159
                if (tmp == &slirp->udb) {
160
                  so = NULL;
161
                } else {
162
                  slirp->udp_last_so = so;
163
                }
164
        }
165

    
166
        if (so == NULL) {
167
          /*
168
           * If there's no socket for this packet,
169
           * create one
170
           */
171
          so = socreate(slirp);
172
          if (!so) {
173
              goto bad;
174
          }
175
          if(udp_attach(so) == -1) {
176
            DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
177
                        errno,strerror(errno)));
178
            sofree(so);
179
            goto bad;
180
          }
181

    
182
          /*
183
           * Setup fields
184
           */
185
          so->so_laddr = ip->ip_src;
186
          so->so_lport = uh->uh_sport;
187

    
188
          if ((so->so_iptos = udp_tos(so)) == 0)
189
            so->so_iptos = ip->ip_tos;
190

    
191
          /*
192
           * XXXXX Here, check if it's in udpexec_list,
193
           * and if it is, do the fork_exec() etc.
194
           */
195
        }
196

    
197
        so->so_faddr = ip->ip_dst; /* XXX */
198
        so->so_fport = uh->uh_dport; /* XXX */
199

    
200
        iphlen += sizeof(struct udphdr);
201
        m->m_len -= iphlen;
202
        m->m_data += iphlen;
203

    
204
        /*
205
         * Now we sendto() the packet.
206
         */
207
        if(sosendto(so,m) == -1) {
208
          m->m_len += iphlen;
209
          m->m_data -= iphlen;
210
          *ip=save_ip;
211
          DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
212
          icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
213
        }
214

    
215
        m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
216

    
217
        /* restore the orig mbuf packet */
218
        m->m_len += iphlen;
219
        m->m_data -= iphlen;
220
        *ip=save_ip;
221
        so->so_m=m;         /* ICMP backup */
222

    
223
        return;
224
bad:
225
        m_free(m);
226
        return;
227
}
228

    
229
int udp_output2(struct socket *so, struct mbuf *m,
230
                struct sockaddr_in *saddr, struct sockaddr_in *daddr,
231
                int iptos)
232
{
233
        register struct udpiphdr *ui;
234
        int error = 0;
235

    
236
        DEBUG_CALL("udp_output");
237
        DEBUG_ARG("so = %lx", (long)so);
238
        DEBUG_ARG("m = %lx", (long)m);
239
        DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr);
240
        DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr);
241

    
242
        /*
243
         * Adjust for header
244
         */
245
        m->m_data -= sizeof(struct udpiphdr);
246
        m->m_len += sizeof(struct udpiphdr);
247

    
248
        /*
249
         * Fill in mbuf with extended UDP header
250
         * and addresses and length put into network format.
251
         */
252
        ui = mtod(m, struct udpiphdr *);
253
    memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
254
        ui->ui_x1 = 0;
255
        ui->ui_pr = IPPROTO_UDP;
256
        ui->ui_len = htons(m->m_len - sizeof(struct ip));
257
        /* XXXXX Check for from-one-location sockets, or from-any-location sockets */
258
        ui->ui_src = saddr->sin_addr;
259
        ui->ui_dst = daddr->sin_addr;
260
        ui->ui_sport = saddr->sin_port;
261
        ui->ui_dport = daddr->sin_port;
262
        ui->ui_ulen = ui->ui_len;
263

    
264
        /*
265
         * Stuff checksum and output datagram.
266
         */
267
        ui->ui_sum = 0;
268
        if ((ui->ui_sum = cksum(m, m->m_len)) == 0)
269
                ui->ui_sum = 0xffff;
270
        ((struct ip *)ui)->ip_len = m->m_len;
271

    
272
        ((struct ip *)ui)->ip_ttl = IPDEFTTL;
273
        ((struct ip *)ui)->ip_tos = iptos;
274

    
275
        error = ip_output(so, m);
276

    
277
        return (error);
278
}
279

    
280
int udp_output(struct socket *so, struct mbuf *m,
281
               struct sockaddr_in *addr)
282

    
283
{
284
    Slirp *slirp = so->slirp;
285
    struct sockaddr_in saddr, daddr;
286

    
287
    saddr = *addr;
288
    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
289
        slirp->vnetwork_addr.s_addr) {
290
        uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
291

    
292
        if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
293
            saddr.sin_addr = slirp->vhost_addr;
294
        } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
295
                   so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
296
            saddr.sin_addr = so->so_faddr;
297
        }
298
    }
299
    daddr.sin_addr = so->so_laddr;
300
    daddr.sin_port = so->so_lport;
301

    
302
    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
303
}
304

    
305
int
306
udp_attach(struct socket *so)
307
{
308
  if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
309
    so->so_expire = curtime + SO_EXPIRE;
310
    insque(so, &so->slirp->udb);
311
  }
312
  return(so->s);
313
}
314

    
315
void
316
udp_detach(struct socket *so)
317
{
318
        closesocket(so->s);
319
        sofree(so);
320
}
321

    
322
static const struct tos_t udptos[] = {
323
        {0, 53, IPTOS_LOWDELAY, 0},                        /* DNS */
324
        {0, 0, 0, 0}
325
};
326

    
327
static uint8_t
328
udp_tos(struct socket *so)
329
{
330
        int i = 0;
331

    
332
        while(udptos[i].tos) {
333
                if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
334
                    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
335
                            so->so_emu = udptos[i].emu;
336
                        return udptos[i].tos;
337
                }
338
                i++;
339
        }
340

    
341
        return 0;
342
}
343

    
344
struct socket *
345
udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
346
           u_int lport, int flags)
347
{
348
        struct sockaddr_in addr;
349
        struct socket *so;
350
        socklen_t addrlen = sizeof(struct sockaddr_in), opt = 1;
351

    
352
        so = socreate(slirp);
353
        if (!so) {
354
            return NULL;
355
        }
356
        so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
357
        so->so_expire = curtime + SO_EXPIRE;
358
        insque(so, &slirp->udb);
359

    
360
        addr.sin_family = AF_INET;
361
        addr.sin_addr.s_addr = haddr;
362
        addr.sin_port = hport;
363

    
364
        if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
365
                udp_detach(so);
366
                return NULL;
367
        }
368
        setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
369

    
370
        getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
371
        so->so_fport = addr.sin_port;
372
        if (addr.sin_addr.s_addr == 0 ||
373
            addr.sin_addr.s_addr == loopback_addr.s_addr) {
374
           so->so_faddr = slirp->vhost_addr;
375
        } else {
376
           so->so_faddr = addr.sin_addr;
377
        }
378
        so->so_lport = lport;
379
        so->so_laddr.s_addr = laddr;
380
        if (flags != SS_FACCEPTONCE)
381
           so->so_expire = 0;
382

    
383
        so->so_state &= SS_PERSISTENT_MASK;
384
        so->so_state |= SS_ISFCONNECTED | flags;
385

    
386
        return so;
387
}