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