~ubuntu-branches/ubuntu/vivid/basilisk2/vivid

« back to all changes in this revision

Viewing changes to src/slirp/slirp.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-03-06 19:33:01 UTC
  • mfrom: (2.1.4 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080306193301-cc2ofn705nfsq3y0
Tags: 0.9.20070407-4
* Update copyright-check cdbs snippet to parse licensecheck using perl:
  + No longer randomly drops newlines
  + More compact hint file (and ordered more like wiki-proposed new copyright
    syntax).
  + No longer ignore files without copyright.
* Update copyright_hints.

Show diffs side-by-side

added added

removed removed

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