11/* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2- Copyright (C)2018,2020-2021 LGB (Gábor Lénárt) <[email protected] > 2+ Copyright (C)2018,2020-2021,2025 LGB (Gábor Lénárt) <[email protected] > 33
44This program is free software; you can redistribute it and/or modify
55it under the terms of the GNU General Public License as published by
@@ -76,6 +76,8 @@ able to configure the device for itself, hmmm ...) */
7676
7777static volatile int tuntap_fd = -1 ;
7878static int nonblocking = 0 ;
79+ static char tuntap_name [32 ];
80+ static struct ifreq ifr ;
7981
8082
8183static int xemu_tuntap_set_nonblocking ( int fd , int is_nonblocking )
@@ -105,62 +107,37 @@ int xemu_tuntap_close ( void )
105107}
106108
107109
108- int xemu_tuntap_read ( void * buffer , int min_size , int max_size )
110+ int xemu_tuntap_read ( void * buffer , const int max_size )
109111{
110- int got = 0 ;
111- if (tuntap_fd < 0 )
112- return 0 ;
113- while (got < min_size ) {
114- int r = read (tuntap_fd , buffer , max_size );
115- printf ("ETH-LOW: read ret %d %s\n" , r , r >= 0 ? "NO-ERROR-CONDITION" : strerror (errno ));
116- if (!r ) {
117- return got ;
118- } else if (r < 0 ) {
119- if (errno == EINTR ) {
120- continue ; // try again if it's interrupted. I am not sure if it's the correct behaviour
121- } else if (errno == EAGAIN || errno == EWOULDBLOCK ) {
122- if (nonblocking )
123- return (got > 0 ) ? got : -2 ; // -2: signal initial EAGAIN situation
124- else
125- return -1 ;
126- } else {
112+ for (;;) {
113+ const int r = read (tuntap_fd , buffer , max_size );
114+ if (r >= 0 ) {
115+ return r ;
116+ } else {
117+ if (errno == EAGAIN || errno == EWOULDBLOCK )
118+ return nonblocking ? -2 : -1 ;
119+ else if (errno != EINTR )
127120 return -1 ;
128- }
121+ // if EINTR: try again if it's interrupted
129122 }
130- max_size -= r ;
131- got += r ;
132- buffer += r ;
133123 }
134- return got ;
135124}
136125
137126
138- int xemu_tuntap_write ( void * buffer , int size )
127+ int xemu_tuntap_write ( const void * buffer , const int size )
139128{
140- int did = 0 ;
141- if (tuntap_fd < 0 )
142- return 0 ;
143- while (size > 0 ) {
144- int w = write (tuntap_fd , buffer , size );
145- if (!w ) {
146- return did ;
147- } else if (w < 0 ) {
148- if (errno == EINTR ) {
149- continue ;
150- } else if (errno == EAGAIN || errno == EWOULDBLOCK ) {
151- if (nonblocking )
152- return (did > 0 ) ? did : -2 ;
153- else
154- return -1 ;
155- } else {
129+ for (;;) {
130+ const int r = write (tuntap_fd , buffer , size );
131+ if (r >= 0 ) {
132+ return r ;
133+ } else {
134+ if (errno == EAGAIN || errno == EWOULDBLOCK )
135+ return nonblocking ? -2 : -1 ;
136+ else if (errno != EINTR )
156137 return -1 ;
157- }
138+ // if EINTR: try again if it's interrupted
158139 }
159- size -= w ;
160- did += w ;
161- buffer += w ;
162140 }
163- return did ;
164141}
165142
166143
@@ -211,7 +188,6 @@ int xemu_tuntap_alloc ( const char *dev_in, char *dev_out, int dev_out_size, uns
211188 return tuntap_fd ;
212189 if (dev_in && strlen (dev_in ) > IFNAMSIZ - 1 )
213190 return -1 ;
214- struct ifreq ifr ;
215191 int fd , err ;
216192 nonblocking = 0 ;
217193 memset (& ifr , 0 , sizeof (ifr ));
@@ -238,13 +214,21 @@ int xemu_tuntap_alloc ( const char *dev_in, char *dev_out, int dev_out_size, uns
238214 close (fd );
239215 return err ;
240216 }
217+ #if 0
218+ int persist = 1 ;
219+ if ((err = ioctl (fd , TUNSETPERSIST , persist )) < 0 ) {
220+ close (fd );
221+ return err ;
222+ }
223+ #endif
241224 if (dev_out ) {
242225 if (strlen (ifr .ifr_name ) >= dev_out_size ) {
243226 close (fd );
244227 return -1 ;
245228 } else
246229 strcpy (dev_out , ifr .ifr_name );
247230 }
231+ snprintf (tuntap_name , sizeof tuntap_name , "%s" , ifr .ifr_name );
248232 if (flags & XEMU_TUNTAP_NONBLOCKING_IO ) {
249233 // sets non blocking I/O up, if requested
250234 if (xemu_tuntap_set_nonblocking (fd , 1 )) {
@@ -256,4 +240,94 @@ int xemu_tuntap_alloc ( const char *dev_in, char *dev_out, int dev_out_size, uns
256240 return fd ; // also return the FD, but note, that it should not be used too much currently outside of this source
257241}
258242
243+
244+ const char * xemu_tuntap_error ( void )
245+ {
246+ return strerror (errno );
247+ }
248+
249+
250+ int xemu_tuntap_get_mac ( unsigned char mac [6 ] )
251+ {
252+ if (ioctl (tuntap_fd , SIOCGIFHWADDR , & ifr ) == -1 )
253+ return -1 ;
254+ memcpy (mac , ifr .ifr_hwaddr .sa_data , 6 );
255+ return 0 ;
256+ }
257+
258+ #include <netinet/in.h>
259+ #include <ifaddrs.h>
260+
261+ unsigned int xemu_tuntap_get_ipv4 ( void )
262+ {
263+ #if 1
264+ int s = socket (AF_INET , SOCK_DGRAM , 0 );
265+ if (ioctl (s , SIOCGIFADDR , & ifr ) == -1 )
266+ return 0 ;
267+ close (s );
268+ struct sockaddr_in * ipaddr = (struct sockaddr_in * )& ifr .ifr_addr ;
269+ return ntohl (ipaddr -> sin_addr .s_addr );
270+ #else
271+ struct ifaddrs * ifaddr ;
272+ if (getifaddrs (& ifaddr ) == -1 )
273+ return 0 ;
274+ for (struct ifaddrs * ifa = ifaddr ; ifa ; ifa = ifa -> ifa_next ) {
275+ if (ifa -> ifa_addr == NULL )
276+ continue ;
277+ if (strcmp (ifa -> ifa_name , tuntap_name ) == 0 && ifa -> ifa_addr -> sa_family == AF_INET ) {
278+ const unsigned int ip = ntohl (((struct sockaddr_in * )ifa -> ifa_addr )-> sin_addr .s_addr );
279+ freeifaddrs (ifaddr );
280+ return ip ;
281+ }
282+ }
283+ freeifaddrs (ifaddr );
284+ return 0 ;
285+ #endif
286+ }
287+
288+
289+ #if 0
290+
291+ // NOTE: this would need to link with -lresolv to be safe, as it's only 1-2 years old change
292+ // in glibc's to have built-in. However that needs my build system a bit!!!! TODO/FIXME
293+ // It seems on BSDs it's always in libreslv, and MacOS is a bit unpredictable in this regard ...
294+
295+ #include <resolv.h>
296+
297+ unsigned int xemu_tuntap_get_dns_server ( void )
298+ {
299+ #if 1
300+ // newer style interface
301+ struct __res_state res ;
302+ const int ret = res_ninit (& res );
303+ const int num = res .nscount ;
304+ # define rres res
305+ #else
306+ // older style interface
307+ const int ret = res_init ();
308+ const int num = _res .nscount ;
309+ # define rres _res
310+ #endif
311+
312+ // TODO: use res_ninit
313+ if (ret ) {
314+ // perror("res_init");
315+ return 0 ;
316+ }
317+ for (int i = 0 ; i < num ; i ++ ) {
318+ const unsigned int ip = ntohl (rres .nsaddr_list [i ].sin_addr .s_addr );
319+ // TODO: allow 127.x.y.z to be returned the caller may use xemu_tuntap_get_ipv4() then to use that for DNS server
320+ if ((ip >> 24 ) != 127 || i == num - 1 )
321+ return ip ;
322+ //char buf[INET6_ADDRSTRLEN];
323+ //if (inet_ntop(AF_INET, &_res.nsaddr_list[i].sin_addr, buf, sizeof(buf))) {
324+ // printf("DNS server: %s\n", buf);
325+ //}
326+ }
327+ return 0 ;
328+ }
329+
330+ #endif
331+
332+
259333#endif
0 commit comments