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