ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/slirp.c
Revision: 1.8
Committed: 2007-11-03T11:11:42Z (17 years ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.7: +6 -1 lines
Log Message:
Update to slirp sources from QEMU 0.8.2:
- set slirp client hostname
- fix slirp redirection on systems without a useful host IP address
- separate alias_addr (10.0.2.2) from our_addr (Ed Swierk)
- fix 32+ KB packets handling (Ed Swierk)
- fix UDP broadcast translation error
- solaris port (Ben Taylor)

File Contents

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