~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to slirp/slirp.c

  • Committer: bellard
  • Date: 2003-07-01 16:27:45 UTC
  • Revision ID: git-v1:7916e2245d71aff10b48aab0ebdc754550c89539
allow up to 256 MB of ram


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@307 c046a42c-6fe2-441c-8c8c-71466251a162

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * libslirp glue
3
 
 *
4
 
 * Copyright (c) 2004-2008 Fabrice Bellard
5
 
 *
6
 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 
 * of this software and associated documentation files (the "Software"), to deal
8
 
 * in the Software without restriction, including without limitation the rights
9
 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 
 * copies of the Software, and to permit persons to whom the Software is
11
 
 * furnished to do so, subject to the following conditions:
12
 
 *
13
 
 * The above copyright notice and this permission notice shall be included in
14
 
 * all copies or substantial portions of the Software.
15
 
 *
16
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 
 * THE SOFTWARE.
23
 
 */
24
 
#include "slirp.h"
25
 
 
26
 
/* host address */
27
 
struct in_addr our_addr;
28
 
/* host dns address */
29
 
struct in_addr dns_addr;
30
 
/* host loopback address */
31
 
struct in_addr loopback_addr;
32
 
 
33
 
/* address for slirp virtual addresses */
34
 
struct in_addr special_addr;
35
 
/* virtual address alias for host */
36
 
struct in_addr alias_addr;
37
 
 
38
 
static const uint8_t special_ethaddr[6] = {
39
 
    0x52, 0x54, 0x00, 0x12, 0x35, 0x00
40
 
};
41
 
 
42
 
/* ARP cache for the guest IP addresses (XXX: allow many entries) */
43
 
uint8_t client_ethaddr[6];
44
 
static struct in_addr client_ipaddr;
45
 
 
46
 
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
47
 
 
48
 
int do_slowtimo;
49
 
int link_up;
50
 
struct timeval tt;
51
 
FILE *lfd;
52
 
struct ex_list *exec_list;
53
 
 
54
 
/* XXX: suppress those select globals */
55
 
fd_set *global_readfds, *global_writefds, *global_xfds;
56
 
 
57
 
char slirp_hostname[33];
58
 
 
59
 
#ifdef _WIN32
60
 
 
61
 
static int get_dns_addr(struct in_addr *pdns_addr)
62
 
{
63
 
    FIXED_INFO *FixedInfo=NULL;
64
 
    ULONG    BufLen;
65
 
    DWORD    ret;
66
 
    IP_ADDR_STRING *pIPAddr;
67
 
    struct in_addr tmp_addr;
68
 
 
69
 
    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
70
 
    BufLen = sizeof(FIXED_INFO);
71
 
 
72
 
    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
73
 
        if (FixedInfo) {
74
 
            GlobalFree(FixedInfo);
75
 
            FixedInfo = NULL;
76
 
        }
77
 
        FixedInfo = GlobalAlloc(GPTR, BufLen);
78
 
    }
79
 
 
80
 
    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
81
 
        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
82
 
        if (FixedInfo) {
83
 
            GlobalFree(FixedInfo);
84
 
            FixedInfo = NULL;
85
 
        }
86
 
        return -1;
87
 
    }
88
 
 
89
 
    pIPAddr = &(FixedInfo->DnsServerList);
90
 
    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
91
 
    *pdns_addr = tmp_addr;
92
 
#if 0
93
 
    printf( "DNS Servers:\n" );
94
 
    printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
95
 
 
96
 
    pIPAddr = FixedInfo -> DnsServerList.Next;
97
 
    while ( pIPAddr ) {
98
 
            printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
99
 
            pIPAddr = pIPAddr ->Next;
100
 
    }
101
 
#endif
102
 
    if (FixedInfo) {
103
 
        GlobalFree(FixedInfo);
104
 
        FixedInfo = NULL;
105
 
    }
106
 
    return 0;
107
 
}
108
 
 
109
 
#else
110
 
 
111
 
static int get_dns_addr(struct in_addr *pdns_addr)
112
 
{
113
 
    char buff[512];
114
 
    char buff2[257];
115
 
    FILE *f;
116
 
    int found = 0;
117
 
    struct in_addr tmp_addr;
118
 
 
119
 
    f = fopen("/etc/resolv.conf", "r");
120
 
    if (!f)
121
 
        return -1;
122
 
 
123
 
#ifdef DEBUG
124
 
    lprint("IP address of your DNS(s): ");
125
 
#endif
126
 
    while (fgets(buff, 512, f) != NULL) {
127
 
        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
128
 
            if (!inet_aton(buff2, &tmp_addr))
129
 
                continue;
130
 
            if (tmp_addr.s_addr == loopback_addr.s_addr)
131
 
                tmp_addr = our_addr;
132
 
            /* If it's the first one, set it to dns_addr */
133
 
            if (!found)
134
 
                *pdns_addr = tmp_addr;
135
 
#ifdef DEBUG
136
 
            else
137
 
                lprint(", ");
138
 
#endif
139
 
            if (++found > 3) {
140
 
#ifdef DEBUG
141
 
                lprint("(more)");
142
 
#endif
143
 
                break;
144
 
            }
145
 
#ifdef DEBUG
146
 
            else
147
 
                lprint("%s", inet_ntoa(tmp_addr));
148
 
#endif
149
 
        }
150
 
    }
151
 
    fclose(f);
152
 
    if (!found)
153
 
        return -1;
154
 
    return 0;
155
 
}
156
 
 
157
 
#endif
158
 
 
159
 
#ifdef _WIN32
160
 
static void slirp_cleanup(void)
161
 
{
162
 
    WSACleanup();
163
 
}
164
 
#endif
165
 
 
166
 
void slirp_init(void)
167
 
{
168
 
    //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
169
 
 
170
 
#ifdef _WIN32
171
 
    {
172
 
        WSADATA Data;
173
 
        WSAStartup(MAKEWORD(2,0), &Data);
174
 
        atexit(slirp_cleanup);
175
 
    }
176
 
#endif
177
 
 
178
 
    link_up = 1;
179
 
 
180
 
    if_init();
181
 
    ip_init();
182
 
 
183
 
    /* Initialise mbufs *after* setting the MTU */
184
 
    m_init();
185
 
 
186
 
    /* set default addresses */
187
 
    inet_aton("127.0.0.1", &loopback_addr);
188
 
 
189
 
    if (get_dns_addr(&dns_addr) < 0) {
190
 
        dns_addr = loopback_addr;
191
 
        fprintf (stderr, "Warning: No DNS servers found\n");
192
 
    }
193
 
 
194
 
    inet_aton(CTL_SPECIAL, &special_addr);
195
 
    alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
196
 
    getouraddr();
197
 
}
198
 
 
199
 
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
200
 
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
201
 
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
202
 
 
203
 
/*
204
 
 * curtime kept to an accuracy of 1ms
205
 
 */
206
 
#ifdef _WIN32
207
 
static void updtime(void)
208
 
{
209
 
    struct _timeb tb;
210
 
 
211
 
    _ftime(&tb);
212
 
    curtime = (u_int)tb.time * (u_int)1000;
213
 
    curtime += (u_int)tb.millitm;
214
 
}
215
 
#else
216
 
static void updtime(void)
217
 
{
218
 
        gettimeofday(&tt, 0);
219
 
 
220
 
        curtime = (u_int)tt.tv_sec * (u_int)1000;
221
 
        curtime += (u_int)tt.tv_usec / (u_int)1000;
222
 
 
223
 
        if ((tt.tv_usec % 1000) >= 500)
224
 
           curtime++;
225
 
}
226
 
#endif
227
 
 
228
 
void slirp_select_fill(int *pnfds,
229
 
                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
230
 
{
231
 
    struct socket *so, *so_next;
232
 
    struct timeval timeout;
233
 
    int nfds;
234
 
    int tmp_time;
235
 
 
236
 
    /* fail safe */
237
 
    global_readfds = NULL;
238
 
    global_writefds = NULL;
239
 
    global_xfds = NULL;
240
 
 
241
 
    nfds = *pnfds;
242
 
        /*
243
 
         * First, TCP sockets
244
 
         */
245
 
        do_slowtimo = 0;
246
 
        if (link_up) {
247
 
                /*
248
 
                 * *_slowtimo needs calling if there are IP fragments
249
 
                 * in the fragment queue, or there are TCP connections active
250
 
                 */
251
 
                do_slowtimo = ((tcb.so_next != &tcb) ||
252
 
                               ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
253
 
 
254
 
                for (so = tcb.so_next; so != &tcb; so = so_next) {
255
 
                        so_next = so->so_next;
256
 
 
257
 
                        /*
258
 
                         * See if we need a tcp_fasttimo
259
 
                         */
260
 
                        if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
261
 
                           time_fasttimo = curtime; /* Flag when we want a fasttimo */
262
 
 
263
 
                        /*
264
 
                         * NOFDREF can include still connecting to local-host,
265
 
                         * newly socreated() sockets etc. Don't want to select these.
266
 
                         */
267
 
                        if (so->so_state & SS_NOFDREF || so->s == -1)
268
 
                           continue;
269
 
 
270
 
                        /*
271
 
                         * Set for reading sockets which are accepting
272
 
                         */
273
 
                        if (so->so_state & SS_FACCEPTCONN) {
274
 
                                FD_SET(so->s, readfds);
275
 
                                UPD_NFDS(so->s);
276
 
                                continue;
277
 
                        }
278
 
 
279
 
                        /*
280
 
                         * Set for writing sockets which are connecting
281
 
                         */
282
 
                        if (so->so_state & SS_ISFCONNECTING) {
283
 
                                FD_SET(so->s, writefds);
284
 
                                UPD_NFDS(so->s);
285
 
                                continue;
286
 
                        }
287
 
 
288
 
                        /*
289
 
                         * Set for writing if we are connected, can send more, and
290
 
                         * we have something to send
291
 
                         */
292
 
                        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
293
 
                                FD_SET(so->s, writefds);
294
 
                                UPD_NFDS(so->s);
295
 
                        }
296
 
 
297
 
                        /*
298
 
                         * Set for reading (and urgent data) if we are connected, can
299
 
                         * receive more, and we have room for it XXX /2 ?
300
 
                         */
301
 
                        if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
302
 
                                FD_SET(so->s, readfds);
303
 
                                FD_SET(so->s, xfds);
304
 
                                UPD_NFDS(so->s);
305
 
                        }
306
 
                }
307
 
 
308
 
                /*
309
 
                 * UDP sockets
310
 
                 */
311
 
                for (so = udb.so_next; so != &udb; so = so_next) {
312
 
                        so_next = so->so_next;
313
 
 
314
 
                        /*
315
 
                         * See if it's timed out
316
 
                         */
317
 
                        if (so->so_expire) {
318
 
                                if (so->so_expire <= curtime) {
319
 
                                        udp_detach(so);
320
 
                                        continue;
321
 
                                } else
322
 
                                        do_slowtimo = 1; /* Let socket expire */
323
 
                        }
324
 
 
325
 
                        /*
326
 
                         * When UDP packets are received from over the
327
 
                         * link, they're sendto()'d straight away, so
328
 
                         * no need for setting for writing
329
 
                         * Limit the number of packets queued by this session
330
 
                         * to 4.  Note that even though we try and limit this
331
 
                         * to 4 packets, the session could have more queued
332
 
                         * if the packets needed to be fragmented
333
 
                         * (XXX <= 4 ?)
334
 
                         */
335
 
                        if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
336
 
                                FD_SET(so->s, readfds);
337
 
                                UPD_NFDS(so->s);
338
 
                        }
339
 
                }
340
 
        }
341
 
 
342
 
        /*
343
 
         * Setup timeout to use minimum CPU usage, especially when idle
344
 
         */
345
 
 
346
 
        /*
347
 
         * First, see the timeout needed by *timo
348
 
         */
349
 
        timeout.tv_sec = 0;
350
 
        timeout.tv_usec = -1;
351
 
        /*
352
 
         * If a slowtimo is needed, set timeout to 500ms from the last
353
 
         * slow timeout. If a fast timeout is needed, set timeout within
354
 
         * 200ms of when it was requested.
355
 
         */
356
 
        if (do_slowtimo) {
357
 
                /* XXX + 10000 because some select()'s aren't that accurate */
358
 
                timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
359
 
                if (timeout.tv_usec < 0)
360
 
                   timeout.tv_usec = 0;
361
 
                else if (timeout.tv_usec > 510000)
362
 
                   timeout.tv_usec = 510000;
363
 
 
364
 
                /* Can only fasttimo if we also slowtimo */
365
 
                if (time_fasttimo) {
366
 
                        tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
367
 
                        if (tmp_time < 0)
368
 
                           tmp_time = 0;
369
 
 
370
 
                        /* Choose the smallest of the 2 */
371
 
                        if (tmp_time < timeout.tv_usec)
372
 
                           timeout.tv_usec = (u_int)tmp_time;
373
 
                }
374
 
        }
375
 
        *pnfds = nfds;
376
 
}
377
 
 
378
 
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
379
 
{
380
 
    struct socket *so, *so_next;
381
 
    int ret;
382
 
 
383
 
    global_readfds = readfds;
384
 
    global_writefds = writefds;
385
 
    global_xfds = xfds;
386
 
 
387
 
        /* Update time */
388
 
        updtime();
389
 
 
390
 
        /*
391
 
         * See if anything has timed out
392
 
         */
393
 
        if (link_up) {
394
 
                if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
395
 
                        tcp_fasttimo();
396
 
                        time_fasttimo = 0;
397
 
                }
398
 
                if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
399
 
                        ip_slowtimo();
400
 
                        tcp_slowtimo();
401
 
                        last_slowtimo = curtime;
402
 
                }
403
 
        }
404
 
 
405
 
        /*
406
 
         * Check sockets
407
 
         */
408
 
        if (link_up) {
409
 
                /*
410
 
                 * Check TCP sockets
411
 
                 */
412
 
                for (so = tcb.so_next; so != &tcb; so = so_next) {
413
 
                        so_next = so->so_next;
414
 
 
415
 
                        /*
416
 
                         * FD_ISSET is meaningless on these sockets
417
 
                         * (and they can crash the program)
418
 
                         */
419
 
                        if (so->so_state & SS_NOFDREF || so->s == -1)
420
 
                           continue;
421
 
 
422
 
                        /*
423
 
                         * Check for URG data
424
 
                         * This will soread as well, so no need to
425
 
                         * test for readfds below if this succeeds
426
 
                         */
427
 
                        if (FD_ISSET(so->s, xfds))
428
 
                           sorecvoob(so);
429
 
                        /*
430
 
                         * Check sockets for reading
431
 
                         */
432
 
                        else if (FD_ISSET(so->s, readfds)) {
433
 
                                /*
434
 
                                 * Check for incoming connections
435
 
                                 */
436
 
                                if (so->so_state & SS_FACCEPTCONN) {
437
 
                                        tcp_connect(so);
438
 
                                        continue;
439
 
                                } /* else */
440
 
                                ret = soread(so);
441
 
 
442
 
                                /* Output it if we read something */
443
 
                                if (ret > 0)
444
 
                                   tcp_output(sototcpcb(so));
445
 
                        }
446
 
 
447
 
                        /*
448
 
                         * Check sockets for writing
449
 
                         */
450
 
                        if (FD_ISSET(so->s, writefds)) {
451
 
                          /*
452
 
                           * Check for non-blocking, still-connecting sockets
453
 
                           */
454
 
                          if (so->so_state & SS_ISFCONNECTING) {
455
 
                            /* Connected */
456
 
                            so->so_state &= ~SS_ISFCONNECTING;
457
 
 
458
 
                            ret = send(so->s, &ret, 0, 0);
459
 
                            if (ret < 0) {
460
 
                              /* XXXXX Must fix, zero bytes is a NOP */
461
 
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
462
 
                                  errno == EINPROGRESS || errno == ENOTCONN)
463
 
                                continue;
464
 
 
465
 
                              /* else failed */
466
 
                              so->so_state = SS_NOFDREF;
467
 
                            }
468
 
                            /* else so->so_state &= ~SS_ISFCONNECTING; */
469
 
 
470
 
                            /*
471
 
                             * Continue tcp_input
472
 
                             */
473
 
                            tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
474
 
                            /* continue; */
475
 
                          } else
476
 
                            ret = sowrite(so);
477
 
                          /*
478
 
                           * XXXXX If we wrote something (a lot), there
479
 
                           * could be a need for a window update.
480
 
                           * In the worst case, the remote will send
481
 
                           * a window probe to get things going again
482
 
                           */
483
 
                        }
484
 
 
485
 
                        /*
486
 
                         * Probe a still-connecting, non-blocking socket
487
 
                         * to check if it's still alive
488
 
                         */
489
 
#ifdef PROBE_CONN
490
 
                        if (so->so_state & SS_ISFCONNECTING) {
491
 
                          ret = recv(so->s, (char *)&ret, 0,0);
492
 
 
493
 
                          if (ret < 0) {
494
 
                            /* XXX */
495
 
                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
496
 
                                errno == EINPROGRESS || errno == ENOTCONN)
497
 
                              continue; /* Still connecting, continue */
498
 
 
499
 
                            /* else failed */
500
 
                            so->so_state = SS_NOFDREF;
501
 
 
502
 
                            /* tcp_input will take care of it */
503
 
                          } else {
504
 
                            ret = send(so->s, &ret, 0,0);
505
 
                            if (ret < 0) {
506
 
                              /* XXX */
507
 
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
508
 
                                  errno == EINPROGRESS || errno == ENOTCONN)
509
 
                                continue;
510
 
                              /* else failed */
511
 
                              so->so_state = SS_NOFDREF;
512
 
                            } else
513
 
                              so->so_state &= ~SS_ISFCONNECTING;
514
 
 
515
 
                          }
516
 
                          tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
517
 
                        } /* SS_ISFCONNECTING */
518
 
#endif
519
 
                }
520
 
 
521
 
                /*
522
 
                 * Now UDP sockets.
523
 
                 * Incoming packets are sent straight away, they're not buffered.
524
 
                 * Incoming UDP data isn't buffered either.
525
 
                 */
526
 
                for (so = udb.so_next; so != &udb; so = so_next) {
527
 
                        so_next = so->so_next;
528
 
 
529
 
                        if (so->s != -1 && FD_ISSET(so->s, readfds)) {
530
 
                            sorecvfrom(so);
531
 
                        }
532
 
                }
533
 
        }
534
 
 
535
 
        /*
536
 
         * See if we can start outputting
537
 
         */
538
 
        if (if_queued && link_up)
539
 
           if_start();
540
 
 
541
 
        /* clear global file descriptor sets.
542
 
         * these reside on the stack in vl.c
543
 
         * so they're unusable if we're not in
544
 
         * slirp_select_fill or slirp_select_poll.
545
 
         */
546
 
         global_readfds = NULL;
547
 
         global_writefds = NULL;
548
 
         global_xfds = NULL;
549
 
}
550
 
 
551
 
#define ETH_ALEN 6
552
 
#define ETH_HLEN 14
553
 
 
554
 
#define ETH_P_IP        0x0800          /* Internet Protocol packet     */
555
 
#define ETH_P_ARP       0x0806          /* Address Resolution packet    */
556
 
 
557
 
#define ARPOP_REQUEST   1               /* ARP request                  */
558
 
#define ARPOP_REPLY     2               /* ARP reply                    */
559
 
 
560
 
struct ethhdr
561
 
{
562
 
        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
563
 
        unsigned char   h_source[ETH_ALEN];     /* source ether addr    */
564
 
        unsigned short  h_proto;                /* packet type ID field */
565
 
};
566
 
 
567
 
struct arphdr
568
 
{
569
 
        unsigned short  ar_hrd;         /* format of hardware address   */
570
 
        unsigned short  ar_pro;         /* format of protocol address   */
571
 
        unsigned char   ar_hln;         /* length of hardware address   */
572
 
        unsigned char   ar_pln;         /* length of protocol address   */
573
 
        unsigned short  ar_op;          /* ARP opcode (command)         */
574
 
 
575
 
         /*
576
 
          *      Ethernet looks like this : This bit is variable sized however...
577
 
          */
578
 
        unsigned char           ar_sha[ETH_ALEN];       /* sender hardware address      */
579
 
        unsigned char           ar_sip[4];              /* sender IP address            */
580
 
        unsigned char           ar_tha[ETH_ALEN];       /* target hardware address      */
581
 
        unsigned char           ar_tip[4];              /* target IP address            */
582
 
};
583
 
 
584
 
static void arp_input(const uint8_t *pkt, int pkt_len)
585
 
{
586
 
    struct ethhdr *eh = (struct ethhdr *)pkt;
587
 
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
588
 
    uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
589
 
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
590
 
    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
591
 
    int ar_op;
592
 
    struct ex_list *ex_ptr;
593
 
 
594
 
    ar_op = ntohs(ah->ar_op);
595
 
    switch(ar_op) {
596
 
    case ARPOP_REQUEST:
597
 
        if (!memcmp(ah->ar_tip, &special_addr, 3)) {
598
 
            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
599
 
                goto arp_ok;
600
 
            for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
601
 
                if (ex_ptr->ex_addr == ah->ar_tip[3])
602
 
                    goto arp_ok;
603
 
            }
604
 
            return;
605
 
        arp_ok:
606
 
            /* XXX: make an ARP request to have the client address */
607
 
            memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
608
 
 
609
 
            /* ARP request for alias/dns mac address */
610
 
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
611
 
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
612
 
            reh->h_source[5] = ah->ar_tip[3];
613
 
            reh->h_proto = htons(ETH_P_ARP);
614
 
 
615
 
            rah->ar_hrd = htons(1);
616
 
            rah->ar_pro = htons(ETH_P_IP);
617
 
            rah->ar_hln = ETH_ALEN;
618
 
            rah->ar_pln = 4;
619
 
            rah->ar_op = htons(ARPOP_REPLY);
620
 
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
621
 
            memcpy(rah->ar_sip, ah->ar_tip, 4);
622
 
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
623
 
            memcpy(rah->ar_tip, ah->ar_sip, 4);
624
 
            slirp_output(arp_reply, sizeof(arp_reply));
625
 
        }
626
 
        break;
627
 
    case ARPOP_REPLY:
628
 
        /* reply to request of client mac address ? */
629
 
        if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
630
 
            !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
631
 
            memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
632
 
        }
633
 
        break;
634
 
    default:
635
 
        break;
636
 
    }
637
 
}
638
 
 
639
 
void slirp_input(const uint8_t *pkt, int pkt_len)
640
 
{
641
 
    struct mbuf *m;
642
 
    int proto;
643
 
 
644
 
    if (pkt_len < ETH_HLEN)
645
 
        return;
646
 
 
647
 
    proto = ntohs(*(uint16_t *)(pkt + 12));
648
 
    switch(proto) {
649
 
    case ETH_P_ARP:
650
 
        arp_input(pkt, pkt_len);
651
 
        break;
652
 
    case ETH_P_IP:
653
 
        m = m_get();
654
 
        if (!m)
655
 
            return;
656
 
        /* Note: we add to align the IP header */
657
 
        m->m_len = pkt_len + 2;
658
 
        memcpy(m->m_data + 2, pkt, pkt_len);
659
 
 
660
 
        m->m_data += 2 + ETH_HLEN;
661
 
        m->m_len -= 2 + ETH_HLEN;
662
 
 
663
 
        ip_input(m);
664
 
        break;
665
 
    default:
666
 
        break;
667
 
    }
668
 
}
669
 
 
670
 
/* output the IP packet to the ethernet device */
671
 
void if_encap(const uint8_t *ip_data, int ip_data_len)
672
 
{
673
 
    uint8_t buf[1600];
674
 
    struct ethhdr *eh = (struct ethhdr *)buf;
675
 
 
676
 
    if (ip_data_len + ETH_HLEN > sizeof(buf))
677
 
        return;
678
 
    
679
 
    if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
680
 
        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
681
 
        struct ethhdr *reh = (struct ethhdr *)arp_req;
682
 
        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
683
 
        const struct ip *iph = (const struct ip *)ip_data;
684
 
 
685
 
        /* If the client addr is not known, there is no point in
686
 
           sending the packet to it. Normally the sender should have
687
 
           done an ARP request to get its MAC address. Here we do it
688
 
           in place of sending the packet and we hope that the sender
689
 
           will retry sending its packet. */
690
 
        memset(reh->h_dest, 0xff, ETH_ALEN);
691
 
        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
692
 
        reh->h_source[5] = CTL_ALIAS;
693
 
        reh->h_proto = htons(ETH_P_ARP);
694
 
        rah->ar_hrd = htons(1);
695
 
        rah->ar_pro = htons(ETH_P_IP);
696
 
        rah->ar_hln = ETH_ALEN;
697
 
        rah->ar_pln = 4;
698
 
        rah->ar_op = htons(ARPOP_REQUEST);
699
 
        /* source hw addr */
700
 
        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
701
 
        rah->ar_sha[5] = CTL_ALIAS;
702
 
        /* source IP */
703
 
        memcpy(rah->ar_sip, &alias_addr, 4);
704
 
        /* target hw addr (none) */
705
 
        memset(rah->ar_tha, 0, ETH_ALEN);
706
 
        /* target IP */
707
 
        memcpy(rah->ar_tip, &iph->ip_dst, 4);
708
 
        client_ipaddr = iph->ip_dst;
709
 
        slirp_output(arp_req, sizeof(arp_req));
710
 
    } else {
711
 
        memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
712
 
        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
713
 
        /* XXX: not correct */
714
 
        eh->h_source[5] = CTL_ALIAS;
715
 
        eh->h_proto = htons(ETH_P_IP);
716
 
        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
717
 
        slirp_output(buf, ip_data_len + ETH_HLEN);
718
 
    }
719
 
}
720
 
 
721
 
int slirp_redir(int is_udp, int host_port,
722
 
                struct in_addr guest_addr, int guest_port)
723
 
{
724
 
    if (is_udp) {
725
 
        if (!udp_listen(htons(host_port), guest_addr.s_addr,
726
 
                        htons(guest_port), 0))
727
 
            return -1;
728
 
    } else {
729
 
        if (!solisten(htons(host_port), guest_addr.s_addr,
730
 
                      htons(guest_port), 0))
731
 
            return -1;
732
 
    }
733
 
    return 0;
734
 
}
735
 
 
736
 
int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
737
 
                  int guest_port)
738
 
{
739
 
    return add_exec(&exec_list, do_pty, (char *)args,
740
 
                    addr_low_byte, htons(guest_port));
741
 
}