1 ////////////////////////////////////////////////////////////////////////////////////
2 //    w32ctca.c    CTCI-W32 (Channel to Channel link to Win32 TCP/IP stack)
3 ////////////////////////////////////////////////////////////////////////////////////
4 // (c) Copyright "Fish" (David B. Trout), 2002-2009. Released under the Q Public License
5 // (http://www.hercules-390.org/herclic.html) as modifications to Hercules.
6 ////////////////////////////////////////////////////////////////////////////////////
7 
8 #include "hstdinc.h"
9 #include "hercules.h"
10 
11 #if !defined(OPTION_W32_CTCI)
12 int w32ctca_dummy = 0;
13 #else // defined(OPTION_W32_CTCI)
14 
15 #include "w32ctca.h"
16 #include "tt32api.h"        // (exported TunTap32.dll functions)
17 #ifdef __CYGWIN__
18   #include <sys/cygwin.h>   // (for cygwin_conv_to_full_win32_path)
19 #endif
20 
21 ///////////////////////////////////////////////////////////////////////////////////////////
22 // We prefer the '_ex' variety as they resolve the "no error" errno issue...
23 // But if they're not available we'll settle for the older version...
24 
25 #define TT32_PROCADDRS( name )                                  \
26                                                                 \
27 ptuntap32_ ## name ## _ex   g_tt32_pfn_ ## name ## _ex = NULL;  \
28 ptuntap32_ ## name          g_tt32_pfn_ ## name        = NULL
29 
30 #define GET_TT32_PROCADDRS( name )                                \
31                                                                   \
32     g_tt32_pfn_ ## name ## _ex  =                                 \
33     (ptuntap32_ ## name ## _ex  ) GetProcAddress( g_tt32_hmoddll, \
34      "tuntap32_" # name   "_ex" );                                \
35     g_tt32_pfn_ ## name         =                                 \
36     (ptuntap32_ ## name         ) GetProcAddress( g_tt32_hmoddll, \
37      "tuntap32_" # name         ); if (!                          \
38     g_tt32_pfn_ ## name         ) goto error
39 
40 ///////////////////////////////////////////////////////////////////////////////////////////
41 // Global variables...
42 
43 #define  TT32_DEFAULT_IFACE     "00-00-5E-80-00-00"
44 
45 CRITICAL_SECTION  g_tt32_lock;   // (lock for accessing ALL below variables)
46 
47 char              g_tt32_dllname [ MAX_TT32_DLLNAMELEN ]  = {0};
48 HMODULE           g_tt32_hmoddll                          = NULL;
49 
50 TT32_PROCADDRS ( open                  );
51 TT32_PROCADDRS ( close                 );
52 TT32_PROCADDRS ( read                  );
53 TT32_PROCADDRS ( write                 );
54 TT32_PROCADDRS ( ioctl                 );
55 TT32_PROCADDRS ( get_stats             );
56 TT32_PROCADDRS ( get_default_iface     );
57 TT32_PROCADDRS ( set_debug_output_func );
58 TT32_PROCADDRS ( version_string        );
59 TT32_PROCADDRS ( version_numbers       );
60 TT32_PROCADDRS ( copyright_string      );
61 
62 // (NOTE: the following function only exists in v3.0+)
63 
64 ptuntap32_build_herc_iface_mac   g_tt32_pfn_build_herc_iface_mac   = NULL;
65 
66 ///////////////////////////////////////////////////////////////////////////////////////////
67 
GetTT32ProcAddrs()68 BOOL GetTT32ProcAddrs()
69 {
70     GET_TT32_PROCADDRS ( open                  );
71     GET_TT32_PROCADDRS ( close                 );
72     GET_TT32_PROCADDRS ( read                  );
73     GET_TT32_PROCADDRS ( write                 );
74     GET_TT32_PROCADDRS ( ioctl                 );
75     GET_TT32_PROCADDRS ( get_stats             );
76     GET_TT32_PROCADDRS ( get_default_iface     );
77     GET_TT32_PROCADDRS ( set_debug_output_func );
78     GET_TT32_PROCADDRS ( version_string        );
79     GET_TT32_PROCADDRS ( version_numbers       );
80     GET_TT32_PROCADDRS ( copyright_string      );
81 
82     // (NOTE: we don't NEED this function (since it's new to
83     //   v3.0+ of tuntap32) so it's okay if it doesn't exist)
84 
85     g_tt32_pfn_build_herc_iface_mac  =
86     (ptuntap32_build_herc_iface_mac  ) GetProcAddress( g_tt32_hmoddll,
87      "tuntap32_build_herc_iface_mac" );
88 
89     LeaveCriticalSection(&g_tt32_lock);
90     return TRUE;
91 
92 error:
93 
94     FreeLibrary( g_tt32_hmoddll );
95     g_tt32_hmoddll = NULL;
96     logmsg( "** tt32_loaddll: One of the GetProcAddress calls failed\n" );
97     LeaveCriticalSection(&g_tt32_lock);
98     return FALSE;
99 }
100 
101 ///////////////////////////////////////////////////////////////////////////////////////////
102 // Debug string output function for use by the TUNTAP32.DLL...
103 
tt32_output_debug_string(const char * debug_string)104 void __cdecl tt32_output_debug_string( const char* debug_string )
105 {
106     logmsg( "%s", debug_string );
107 }
108 
enable_tt32_debug_tracing(int enable)109 void  enable_tt32_debug_tracing( int enable )
110 {
111     // Pass to TunTap32 DLL a pointer to the function it can use to
112     // display debug messages with. This function of our's (that we
113     // are passing it a pointer to) will then display its debugging
114     // message (string) on the Hercules console so we can see it.
115 
116     g_tt32_pfn_set_debug_output_func( enable ? &tt32_output_debug_string : NULL );
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////////////////
120 // Load the TUNTAP32.DLL...
121 
tt32_loaddll()122 BOOL tt32_loaddll()
123 {
124     char*  pszDLLName;
125     char   tt32_dllname_in_buff  [ MAX_PATH ];
126     char   tt32_dllname_out_buff [ MAX_PATH ] = {0};
127     static int tt32_init_done = 0;
128 
129     if (!tt32_init_done)
130     {
131         InitializeCriticalSection( &g_tt32_lock );
132         tt32_init_done = 1;
133     }
134 
135     EnterCriticalSection(&g_tt32_lock);
136 
137     if (g_tt32_hmoddll)
138     {
139         LeaveCriticalSection(&g_tt32_lock);
140         return TRUE;
141     }
142 
143     // First, determine the name of the DLL we should try loading...
144 
145     if ( !( pszDLLName = getenv( "HERCULES_IFC" ) ) )
146         pszDLLName = DEF_TT32_DLLNAME;
147 
148     ASSERT( pszDLLName && *pszDLLName );
149 
150     // Then check to see if the "name" contains path information or not...
151 
152     if ( strchr( pszDLLName, '/' ) || strchr( pszDLLName, '\\' ) )
153     {
154         // It's already a path...
155         strlcpy( tt32_dllname_in_buff, pszDLLName, sizeof(tt32_dllname_in_buff) );
156     }
157     else
158     {
159         // It's not a path, so make it one...
160         strlcpy( tt32_dllname_in_buff, MODULESDIR, sizeof(tt32_dllname_in_buff) );
161         strlcat( tt32_dllname_in_buff,     "/"   , sizeof(tt32_dllname_in_buff) );
162         strlcat( tt32_dllname_in_buff, pszDLLName, sizeof(tt32_dllname_in_buff) );
163     }
164 
165     // Now convert it to a full path...
166 
167     // PROGRAMMING NOTE: It's important here to ensure that our end result is a path
168     // with BACKWARD slashes in it and NOT forward slashes! LoadLibrary is one of the
169     // few Win32 functions that cannot handle paths with forward slashes in it. For
170     // 'open', etc, yeah, forward slashes are fine, but for LoadLibrary they're not!
171 
172 #ifdef _MSVC_
173     if ( !_fullpath( tt32_dllname_out_buff, tt32_dllname_in_buff, sizeof(tt32_dllname_out_buff) ) )
174         strlcpy(     tt32_dllname_out_buff, tt32_dllname_in_buff, sizeof(tt32_dllname_out_buff) );
175 #else // (presumed cygwin)
176     cygwin_conv_to_full_win32_path( tt32_dllname_in_buff, tt32_dllname_out_buff );
177 #endif // _MSVC_
178 
179     tt32_dllname_out_buff[ sizeof(tt32_dllname_out_buff) - 1 ] = 0;
180 
181     // Finally, copy it to our global home for it...
182 
183     strlcpy( g_tt32_dllname, tt32_dllname_out_buff, sizeof(g_tt32_dllname) );
184 
185     ASSERT(g_tt32_dllname[0]);
186 
187     g_tt32_hmoddll = LoadLibraryEx( g_tt32_dllname, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
188 
189     if (!g_tt32_hmoddll)
190     {
191         // Try again WITHOUT the path this time...
192 
193         strlcpy( g_tt32_dllname, pszDLLName, sizeof(g_tt32_dllname) );
194 
195         g_tt32_hmoddll = LoadLibraryEx( g_tt32_dllname, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
196 
197         if (!g_tt32_hmoddll)
198         {
199             DWORD dwLastError = GetLastError();
200             LeaveCriticalSection(&g_tt32_lock);
201             logmsg("** tt32_loaddll: LoadLibraryEx(\"%s\") failed; rc=%ld: %s\n",
202                 g_tt32_dllname,dwLastError,strerror(dwLastError));
203             return FALSE;
204         }
205     }
206 
207     // Resolve our required DLL entry-point variables...
208 
209     if (!GetTT32ProcAddrs())
210         return FALSE;
211 
212     logmsg("%s version %s initiated\n",
213         g_tt32_dllname,
214         g_tt32_pfn_version_string());
215 
216 #if defined(DEBUG) || defined(_DEBUG)
217     enable_tt32_debug_tracing(1);   // (enable debug tracing by default for DEBUG builds)
218 #endif
219 
220     return TRUE;
221 }
222 
223 ///////////////////////////////////////////////////////////////////////////////////////////
224 
tt32_open(char * pszGatewayDevice,int iFlags)225 int  tt32_open( char* pszGatewayDevice, int iFlags )
226 {
227     int rc, errnum;
228     if (!tt32_loaddll()) return -1;
229     if (!      g_tt32_pfn_open_ex )
230         return g_tt32_pfn_open    ( pszGatewayDevice, iFlags );
231     rc    =    g_tt32_pfn_open_ex ( pszGatewayDevice, iFlags, &errnum );
232     errno =                                                    errnum;
233     return rc;
234 }
235 
236 ///////////////////////////////////////////////////////////////////////////////////////////
237 
tt32_read(int fd,u_char * buffer,u_long size)238 int  tt32_read( int fd, u_char* buffer, u_long size )
239 {
240     int rc, errnum;
241     if (!tt32_loaddll()) return -1;
242     if (!      g_tt32_pfn_read_ex )
243         return g_tt32_pfn_read    ( fd, buffer, size );
244     rc    =    g_tt32_pfn_read_ex ( fd, buffer, size, &errnum );
245     errno =                                            errnum;
246     return rc;
247 }
248 
249 ///////////////////////////////////////////////////////////////////////////////////////////
250 
tt32_write(int fd,u_char * buffer,u_long size)251 int  tt32_write( int fd, u_char* buffer, u_long size )
252 {
253     int rc, errnum;
254     if (!tt32_loaddll()) return -1;
255     if (!      g_tt32_pfn_write_ex )
256         return g_tt32_pfn_write    ( fd, buffer, size );
257     rc    =    g_tt32_pfn_write_ex ( fd, buffer, size, &errnum );
258     errno =                                             errnum;
259     return rc;
260 }
261 
262 ///////////////////////////////////////////////////////////////////////////////////////////
263 
tt32_close(int fd)264 int  tt32_close( int fd )
265 {
266     int rc, errnum;
267     if (!tt32_loaddll()) return -1;
268 #if defined(DEBUG) || defined(_DEBUG)
269     display_tt32_stats(fd);
270 #endif
271     if (!      g_tt32_pfn_close_ex )
272         return g_tt32_pfn_close    ( fd );
273     rc    =    g_tt32_pfn_close_ex ( fd, &errnum );
274     errno =                               errnum;
275     return rc;
276 }
277 
278 ///////////////////////////////////////////////////////////////////////////////////////////
279 
tt32_ioctl(int fd,int iRequest,char * argp)280 int  tt32_ioctl( int fd, int iRequest, char* argp )
281 {
282     int rc, errnum;
283     if (!tt32_loaddll()) return -1;
284     if (!      g_tt32_pfn_ioctl_ex )
285         return g_tt32_pfn_ioctl    ( fd, iRequest, argp );
286     rc    =    g_tt32_pfn_ioctl_ex ( fd, iRequest, argp, &errnum );
287     errno =                                               errnum;
288     return rc;
289 }
290 
291 ///////////////////////////////////////////////////////////////////////////////////////////
292 
tt32_get_default_iface()293 const char*  tt32_get_default_iface()
294 {
295     int errnum;
296     const char* pszDefaultIFace = NULL;
297     if (tt32_loaddll())
298     {
299         if (!                    g_tt32_pfn_get_default_iface_ex )
300                pszDefaultIFace = g_tt32_pfn_get_default_iface    ();
301         else { pszDefaultIFace = g_tt32_pfn_get_default_iface_ex ( &errnum );
302             errno =                                                 errnum;
303         }
304     }
305     return ( pszDefaultIFace ? pszDefaultIFace : TT32_DEFAULT_IFACE );
306 }
307 
308 ///////////////////////////////////////////////////////////////////////////////////////////
309 
display_tt32_stats(int fd)310 int  display_tt32_stats( int fd )
311 {
312     int errnum;
313     TT32STATS stats;
314 
315     if (!tt32_loaddll()) return -1;
316 
317     memset(&stats,0,sizeof(stats));
318     stats.dwStructSize = sizeof(stats);
319 
320     if (!  g_tt32_pfn_get_stats_ex )
321            g_tt32_pfn_get_stats    ( fd, &stats );
322     else { g_tt32_pfn_get_stats_ex ( fd, &stats, &errnum );
323         errno =                                   errnum;
324     }
325 
326     if (stats.dwStructSize >= sizeof(stats))
327     {
328         // New version 3.3 stats
329 
330         logmsg
331         (
332             "\n%s Statistics:\n\n"
333 
334             "Size of Kernel Hold Buffer:      %5luK\n"
335             "Size of DLL I/O Buffer:          %5luK\n"
336             "Maximum DLL I/O Bytes Received:  %5luK\n\n"
337 
338             "%12" I64_FMT "d  Total Write Calls\n"
339             "%12" I64_FMT "d  Total Write I/Os\n"
340             "%12" I64_FMT "d  Packets To All Zeroes MAC Written\n"
341             "%12" I64_FMT "d  Total Packets Written\n"
342             "%12" I64_FMT "d  Total Bytes Written\n\n"
343 
344             "%12" I64_FMT "d  Total Read Calls\n"
345             "%12" I64_FMT "d  Total Read I/Os\n"
346             "%12" I64_FMT "d  Internally Handled ARP Packets\n"
347             "%12" I64_FMT "d  Packets From Ourself\n"
348             "%12" I64_FMT "d  Total Ignored Packets\n"
349             "%12" I64_FMT "d  Packets To All Zeroes MAC Read\n"
350             "%12" I64_FMT "d  Total Packets Read\n"
351             "%12" I64_FMT "d  Total Bytes Read\n\n"
352 
353             ,g_tt32_dllname
354 
355             ,(stats.dwKernelBuffSize   + 1023) / 1024
356             ,(stats.dwReadBuffSize     + 1023) / 1024
357             ,(stats.dwMaxBytesReceived + 1023) / 1024
358 
359             ,stats.n64WriteCalls
360             ,stats.n64WriteIOs
361             ,stats.n64ZeroMACPacketsWritten
362             ,stats.n64PacketsWritten
363             ,stats.n64BytesWritten
364 
365             ,stats.n64ReadCalls
366             ,stats.n64ReadIOs
367             ,stats.n64InternalPackets
368             ,stats.n64OwnPacketsIgnored
369             ,stats.n64IgnoredPackets
370             ,stats.n64ZeroMACPacketsRead
371             ,stats.n64PacketsRead
372             ,stats.n64BytesRead
373         );
374     }
375     else
376     {
377         // Old pre version 3.3 stats
378 
379         logmsg
380         (
381             "\n%s Statistics:\n\n"
382 
383             "Size of Kernel Hold Buffer:      %5luK\n"
384             "Size of DLL I/O Buffer:          %5luK\n"
385             "Maximum DLL I/O Bytes Received:  %5luK\n\n"
386 
387             "%12" I64_FMT "d Write Calls\n"
388             "%12" I64_FMT "d Write I/Os\n"
389             "%12" I64_FMT "d Read Calls\n"
390             "%12" I64_FMT "d Read I/Os\n"
391             "%12" I64_FMT "d Packets Read\n"
392             "%12" I64_FMT "d Packets Written\n"
393             "%12" I64_FMT "d Bytes Read\n"
394             "%12" I64_FMT "d Bytes Written\n"
395             "%12" I64_FMT "d Internal Packets\n"
396             "%12" I64_FMT "d Ignored Packets\n\n"
397             ,
398             g_tt32_dllname
399             ,(stats.dwKernelBuffSize   + 1023) / 1024
400             ,(stats.dwReadBuffSize     + 1023) / 1024
401             ,(stats.dwMaxBytesReceived + 1023) / 1024
402             ,stats.n64WriteCalls
403             ,stats.n64WriteIOs
404             ,stats.n64ReadCalls
405             ,stats.n64ReadIOs
406             ,stats.n64PacketsRead
407             ,stats.n64PacketsWritten
408             ,stats.n64BytesRead
409             ,stats.n64BytesWritten
410             ,stats.n64InternalPackets
411             ,stats.n64IgnoredPackets
412         );
413     }
414 
415     return 0;
416 }
417 
418 ///////////////////////////////////////////////////////////////////////////////////////////
419 // BOOLEAN FUNCTION
420 
tt32_build_herc_iface_mac(BYTE * out_mac,const BYTE * in_ip)421 int tt32_build_herc_iface_mac ( BYTE* out_mac, const BYTE* in_ip )
422 {
423     // We prefer to let TunTap32 do it for us (since IT'S the one
424     // that decides what it should really be) but if they're using
425     // an older version of TunTap32 that doesn't have the function
426     // then we'll do it ourselves just like before...
427 
428     if (!g_tt32_pfn_build_herc_iface_mac)
429         return 0;   // (FALSE: must do it yourself)
430 
431     g_tt32_pfn_build_herc_iface_mac( out_mac, in_ip );
432     return 1;       // (TRUE: ok we did it for you)
433 }
434 
435 ///////////////////////////////////////////////////////////////////////////////////////////
436 
437 #endif // !defined(OPTION_W32_CTCI)
438 
439 ///////////////////////////////////////////////////////////////////////////////////////////
440