symbian-qemu-0.9.1-12/qemu-symbian-svp/slirp/slirp.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     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         if (M_FREEROOM(m) < pkt_len + 2) {
       
   658             m_inc(m, pkt_len + 2);
       
   659         }
       
   660         m->m_len = pkt_len + 2;
       
   661         memcpy(m->m_data + 2, pkt, pkt_len);
       
   662 
       
   663         m->m_data += 2 + ETH_HLEN;
       
   664         m->m_len -= 2 + ETH_HLEN;
       
   665 
       
   666         ip_input(m);
       
   667         break;
       
   668     default:
       
   669         break;
       
   670     }
       
   671 }
       
   672 
       
   673 /* output the IP packet to the ethernet device */
       
   674 void if_encap(const uint8_t *ip_data, int ip_data_len)
       
   675 {
       
   676     uint8_t buf[1600];
       
   677     struct ethhdr *eh = (struct ethhdr *)buf;
       
   678 
       
   679     if (ip_data_len + ETH_HLEN > sizeof(buf))
       
   680         return;
       
   681     
       
   682     if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
       
   683         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
       
   684         struct ethhdr *reh = (struct ethhdr *)arp_req;
       
   685         struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
       
   686         const struct ip *iph = (const struct ip *)ip_data;
       
   687 
       
   688         /* If the client addr is not known, there is no point in
       
   689            sending the packet to it. Normally the sender should have
       
   690            done an ARP request to get its MAC address. Here we do it
       
   691            in place of sending the packet and we hope that the sender
       
   692            will retry sending its packet. */
       
   693         memset(reh->h_dest, 0xff, ETH_ALEN);
       
   694         memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
       
   695         reh->h_source[5] = CTL_ALIAS;
       
   696         reh->h_proto = htons(ETH_P_ARP);
       
   697         rah->ar_hrd = htons(1);
       
   698         rah->ar_pro = htons(ETH_P_IP);
       
   699         rah->ar_hln = ETH_ALEN;
       
   700         rah->ar_pln = 4;
       
   701         rah->ar_op = htons(ARPOP_REQUEST);
       
   702         /* source hw addr */
       
   703         memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
       
   704         rah->ar_sha[5] = CTL_ALIAS;
       
   705         /* source IP */
       
   706         memcpy(rah->ar_sip, &alias_addr, 4);
       
   707         /* target hw addr (none) */
       
   708         memset(rah->ar_tha, 0, ETH_ALEN);
       
   709         /* target IP */
       
   710         memcpy(rah->ar_tip, &iph->ip_dst, 4);
       
   711         client_ipaddr = iph->ip_dst;
       
   712         slirp_output(arp_req, sizeof(arp_req));
       
   713     } else {
       
   714         memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
       
   715         memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
       
   716         /* XXX: not correct */
       
   717         eh->h_source[5] = CTL_ALIAS;
       
   718         eh->h_proto = htons(ETH_P_IP);
       
   719         memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
       
   720         slirp_output(buf, ip_data_len + ETH_HLEN);
       
   721     }
       
   722 }
       
   723 
       
   724 int slirp_redir(int is_udp, int host_port,
       
   725                 struct in_addr guest_addr, int guest_port)
       
   726 {
       
   727     if (is_udp) {
       
   728         if (!udp_listen(htons(host_port), guest_addr.s_addr,
       
   729                         htons(guest_port), 0))
       
   730             return -1;
       
   731     } else {
       
   732         if (!solisten(htons(host_port), guest_addr.s_addr,
       
   733                       htons(guest_port), 0))
       
   734             return -1;
       
   735     }
       
   736     return 0;
       
   737 }
       
   738 
       
   739 int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
       
   740                   int guest_port)
       
   741 {
       
   742     return add_exec(&exec_list, do_pty, (char *)args,
       
   743                     addr_low_byte, htons(guest_port));
       
   744 }