- define additional shell paths for CSIDL_... constants
[wine] / dlls / kernel / device.c
1 /*
2  * Win32 device functions
3  *
4  * Copyright 1998 Marcus Meissner
5  * Copyright 1998 Ulrich Weigand
6  * Copyright 1998 Patrik Stridvall
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 # include <arpa/inet.h>
39 #endif
40 #include <string.h>
41 #include <stdarg.h>
42 #include <time.h>
43
44 #include "ntstatus.h"
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winreg.h"
48 #include "winerror.h"
49 #include "winnls.h"
50 #include "file.h"
51 #include "winioctl.h"
52 #include "winnt.h"
53 #include "iphlpapi.h"
54 #include "kernel_private.h"
55 #include "wine/server.h"
56 #include "wine/debug.h"
57
58 WINE_DEFAULT_DEBUG_CHANNEL(file);
59
60 #ifndef INADDR_NONE
61 #define INADDR_NONE ~0UL
62 #endif
63
64 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode,
65                               LPVOID lpvInBuffer, DWORD cbInBuffer,
66                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
67                               LPDWORD lpcbBytesReturned,
68                               LPOVERLAPPED lpOverlapped);
69 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
70                               LPVOID lpvInBuffer, DWORD cbInBuffer,
71                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
72                               LPDWORD lpcbBytesReturned,
73                               LPOVERLAPPED lpOverlapped);
74 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
75                               LPVOID lpvInBuffer, DWORD cbInBuffer,
76                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
77                               LPDWORD lpcbBytesReturned,
78                               LPOVERLAPPED lpOverlapped);
79
80 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode,
81                               LPVOID lpvInBuffer, DWORD cbInBuffer,
82                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
83                               LPDWORD lpcbBytesReturned,
84                               LPOVERLAPPED lpOverlapped);
85
86 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
87                               LPVOID lpvInBuffer, DWORD cbInBuffer,
88                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
89                               LPDWORD lpcbBytesReturned,
90                               LPOVERLAPPED lpOverlapped);
91
92 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
93                               LPVOID lpvInBuffer, DWORD cbInBuffer,
94                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
95                               LPDWORD lpcbBytesReturned,
96                               LPOVERLAPPED lpOverlapped);
97
98 static BOOL DeviceIo_DHCP(DWORD dwIoControlCode,
99                               LPVOID lpvInBuffer, DWORD cbInBuffer,
100                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
101                               LPDWORD lpcbBytesReturned,
102                               LPOVERLAPPED lpOverlapped);
103
104 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
105                               LPVOID lpvInBuffer, DWORD cbInBuffer,
106                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
107                               LPDWORD lpcbBytesReturned,
108                               LPOVERLAPPED lpOverlapped);
109
110 static BOOL DeviceIo_HASP (DWORD dwIoControlCode,
111                               LPVOID lpvInBuffer, DWORD cbInBuffer,
112                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
113                               LPDWORD lpcbBytesReturned,
114                               LPOVERLAPPED lpOverlapped);
115
116 static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode,
117                               LPVOID lpvInBuffer, DWORD cbInBuffer,
118                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
119                               LPDWORD lpcbBytesReturned,
120                               LPOVERLAPPED lpOverlapped);
121
122 static BOOL DeviceIo_VNB(DWORD dwIoControlCode,
123                               LPVOID lpvInBuffer, DWORD cbInBuffer,
124                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
125                               LPDWORD lpcbBytesReturned,
126                               LPOVERLAPPED lpOverlapped);
127
128 /*
129  * VxD names are taken from the Win95 DDK
130  */
131
132 struct VxDInfo
133 {
134     LPCSTR  name;
135     WORD    id;
136     BOOL  (*deviceio)(DWORD, LPVOID, DWORD,
137                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
138 };
139
140 static const struct VxDInfo VxDList[] =
141 {
142     /* Standard VxD IDs */
143     { "VMM",      0x0001, NULL },
144     { "DEBUG",    0x0002, NULL },
145     { "VPICD",    0x0003, NULL },
146     { "VDMAD",    0x0004, NULL },
147     { "VTD",      0x0005, NULL },
148     { "V86MMGR",  0x0006, NULL },
149     { "PAGESWAP", 0x0007, NULL },
150     { "PARITY",   0x0008, NULL },
151     { "REBOOT",   0x0009, NULL },
152     { "VDD",      0x000A, NULL },
153     { "VSD",      0x000B, NULL },
154     { "VMD",      0x000C, NULL },
155     { "VKD",      0x000D, NULL },
156     { "VCD",      0x000E, DeviceIo_VCD },
157     { "VPD",      0x000F, NULL },
158     { "BLOCKDEV", 0x0010, NULL },
159     { "VMCPD",    0x0011, NULL },
160     { "EBIOS",    0x0012, NULL },
161     { "BIOSXLAT", 0x0013, NULL },
162     { "VNETBIOS", 0x0014, DeviceIo_NetBIOS },
163     { "DOSMGR",   0x0015, NULL },
164     { "WINLOAD",  0x0016, NULL },
165     { "SHELL",    0x0017, NULL },
166     { "VMPOLL",   0x0018, NULL },
167     { "VPROD",    0x0019, NULL },
168     { "DOSNET",   0x001A, NULL },
169     { "VFD",      0x001B, NULL },
170     { "VDD2",     0x001C, NULL },
171     { "WINDEBUG", 0x001D, NULL },
172     { "TSRLOAD",  0x001E, NULL },
173     { "BIOSHOOK", 0x001F, NULL },
174     { "INT13",    0x0020, NULL },
175     { "PAGEFILE", 0x0021, NULL },
176     { "SCSI",     0x0022, NULL },
177     { "MCA_POS",  0x0023, NULL },
178     { "SCSIFD",   0x0024, NULL },
179     { "VPEND",    0x0025, NULL },
180     { "VPOWERD",  0x0026, NULL },
181     { "VXDLDR",   0x0027, NULL },
182     { "NDIS",     0x0028, NULL },
183     { "BIOS_EXT", 0x0029, NULL },
184     { "VWIN32",   0x002A, DeviceIo_VWin32 },
185     { "VCOMM",    0x002B, NULL },
186     { "SPOOLER",  0x002C, NULL },
187     { "WIN32S",   0x002D, NULL },
188     { "DEBUGCMD", 0x002E, NULL },
189
190     { "VNB",      0x0031, DeviceIo_VNB },
191     { "SERVER",   0x0032, NULL },
192     { "CONFIGMG", 0x0033, NULL },
193     { "DWCFGMG",  0x0034, NULL },
194     { "SCSIPORT", 0x0035, NULL },
195     { "VFBACKUP", 0x0036, NULL },
196     { "ENABLE",   0x0037, NULL },
197     { "VCOND",    0x0038, NULL },
198
199     { "EFAX",     0x003A, NULL },
200     { "DSVXD",    0x003B, NULL },
201     { "ISAPNP",   0x003C, NULL },
202     { "BIOS",     0x003D, NULL },
203     { "WINSOCK",  0x003E, NULL },
204     { "WSOCK",    0x003E, NULL },
205     { "WSIPX",    0x003F, NULL },
206     { "IFSMgr",   0x0040, DeviceIo_IFSMgr },
207     { "VCDFSD",   0x0041, NULL },
208     { "MRCI2",    0x0042, NULL },
209     { "PCI",      0x0043, NULL },
210     { "PELOADER", 0x0044, NULL },
211     { "EISA",     0x0045, NULL },
212     { "DRAGCLI",  0x0046, NULL },
213     { "DRAGSRV",  0x0047, NULL },
214     { "PERF",     0x0048, NULL },
215     { "AWREDIR",  0x0049, NULL },
216
217     /* Far East support */
218     { "ETEN",     0x0060, NULL },
219     { "CHBIOS",   0x0061, NULL },
220     { "VMSGD",    0x0062, NULL },
221     { "VPPID",    0x0063, NULL },
222     { "VIME",     0x0064, NULL },
223     { "VHBIOSD",  0x0065, NULL },
224
225     /* Multimedia OEM IDs */
226     { "VTDAPI",   0x0442, DeviceIo_VTDAPI },
227     { "MMDEVLDR", 0x044A, DeviceIo_MMDEVLDR },
228
229     /* Network Device IDs */
230     { "VNetSup",  0x0480, NULL },
231     { "VRedir",   0x0481, NULL },
232     { "VBrowse",  0x0482, NULL },
233     { "VSHARE",   0x0483, NULL },
234     { "IFSMgr",   0x0484, NULL },
235     { "MEMPROBE", 0x0485, NULL },
236     { "VFAT",     0x0486, NULL },
237     { "NWLINK",   0x0487, NULL },
238     { "VNWLINK",  0x0487, NULL },
239     { "NWSUP",    0x0487, NULL },
240     { "VTDI",     0x0488, NULL },
241     { "VIP",      0x0489, NULL },
242     { "VTCP",     0x048A, NULL },
243     { "VCache",   0x048B, NULL },
244     { "VUDP",     0x048C, NULL },
245     { "VAsync",   0x048D, NULL },
246     { "NWREDIR",  0x048E, NULL },
247     { "STAT80",   0x048F, NULL },
248     { "SCSIPORT", 0x0490, NULL },
249     { "FILESEC",  0x0491, NULL },
250     { "NWSERVER", 0x0492, NULL },
251     { "SECPROV",  0x0493, NULL },
252     { "NSCL",     0x0494, NULL },
253     { "WSTCP",    0x0495, NULL },
254     { "NDIS2SUP", 0x0496, NULL },
255     { "MSODISUP", 0x0497, NULL },
256     { "Splitter", 0x0498, NULL },
257     { "PPP",      0x0499, NULL },
258     { "VDHCP",    0x049A, DeviceIo_DHCP },
259     { "VNBT",     0x049B, NULL },
260     { "LOGGER",   0x049D, NULL },
261     { "EFILTER",  0x049E, NULL },
262     { "FFILTER",  0x049F, NULL },
263     { "TFILTER",  0x04A0, NULL },
264     { "AFILTER",  0x04A1, NULL },
265     { "IRLAMP",   0x04A2, NULL },
266
267     { "PCCARD",   0x097C, DeviceIo_PCCARD },
268     { "HASP95",   0x3721, DeviceIo_HASP },
269
270     /* WINE additions, ids unknown */
271     { "MONODEBG.VXD", 0x4242, DeviceIo_MONODEBG },
272
273     { NULL,       0,      NULL }
274 };
275
276 HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa )
277 {
278     const struct VxDInfo *info;
279     char filename[MAX_PATH];
280
281     if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL))
282     {
283         SetLastError( ERROR_FILE_NOT_FOUND );
284         return 0;
285     }
286
287     for (info = VxDList; info->name; info++)
288         if (!strncasecmp( info->name, filename, strlen(info->name) ))
289             return FILE_CreateDevice( info->id | 0x10000, access, sa );
290
291     FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
292            filename);
293
294     SetLastError( ERROR_FILE_NOT_FOUND );
295     return 0;
296 }
297
298 static DWORD DEVICE_GetClientID( HANDLE handle )
299 {
300     DWORD       ret = 0;
301     SERVER_START_REQ( get_device_id )
302     {
303         req->handle = handle;
304         if (!wine_server_call( req )) ret = reply->id;
305     }
306     SERVER_END_REQ;
307     return ret;
308 }
309
310 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
311 {
312     const struct VxDInfo *info = NULL;
313
314     if (clientID & 0x10000)
315     {
316         for (info = VxDList; info->name; info++)
317             if (info->id == LOWORD(clientID)) break;
318     }
319     return info;
320 }
321
322 /****************************************************************************
323  *              DeviceIoControl (KERNEL32.@)
324  * This is one of those big ugly nasty procedure which can do
325  * a million and one things when it comes to devices. It can also be
326  * used for VxD communication.
327  *
328  * A return value of FALSE indicates that something has gone wrong which
329  * GetLastError can decipher.
330  */
331 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
332                               LPVOID lpvInBuffer, DWORD cbInBuffer,
333                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
334                               LPDWORD lpcbBytesReturned,
335                               LPOVERLAPPED lpOverlapped)
336 {
337         DWORD clientID;
338
339         TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n",
340                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
341                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
342
343         if (!(clientID = DEVICE_GetClientID( hDevice )))
344         {
345                 SetLastError( ERROR_INVALID_PARAMETER );
346                 return FALSE;
347         }
348
349         /* Check if this is a user defined control code for a VxD */
350         if( HIWORD( dwIoControlCode ) == 0 )
351         {
352                 const struct VxDInfo *info;
353                 if (!(info = DEVICE_GetInfo( clientID )))
354                 {
355                         FIXME( "No device found for id %lx\n", clientID);
356                 }
357                 else if ( info->deviceio )
358                 {
359                         return info->deviceio( dwIoControlCode,
360                                         lpvInBuffer, cbInBuffer,
361                                         lpvOutBuffer, cbOutBuffer,
362                                         lpcbBytesReturned, lpOverlapped );
363                 }
364                 else
365                 {
366                         FIXME( "Unimplemented control %ld for VxD device %s\n",
367                                dwIoControlCode, info->name ? info->name : "???" );
368                         /* FIXME: this is for invalid calls on W98SE,
369                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
370                          * instead ? */
371                         SetLastError( ERROR_INVALID_FUNCTION );
372                 }
373         }
374         else
375         {       
376             NTSTATUS            status;
377
378             if (lpOverlapped)
379             {
380                 status = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, 
381                                                NULL, NULL, 
382                                                (PIO_STATUS_BLOCK)lpOverlapped,
383                                                dwIoControlCode, 
384                                                lpvInBuffer, cbInBuffer,
385                                                lpvOutBuffer, cbOutBuffer);
386                 if (status) SetLastError(RtlNtStatusToDosError(status));
387                 if (lpcbBytesReturned) *lpcbBytesReturned = lpOverlapped->InternalHigh;
388                 return !status;
389             }
390             else
391             {
392                 IO_STATUS_BLOCK     iosb;
393
394                 status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb,
395                                                dwIoControlCode, 
396                                                lpvInBuffer, cbInBuffer,
397                                                lpvOutBuffer, cbOutBuffer);
398                 if (status) SetLastError(RtlNtStatusToDosError(status));
399                 if (lpcbBytesReturned) *lpcbBytesReturned = iosb.Information;
400                 return !status;
401             }
402         }
403         return FALSE;
404 }
405
406 /***********************************************************************
407  *           DeviceIo_VTDAPI
408  */
409 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
410                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
411                               LPDWORD lpcbBytesReturned,
412                               LPOVERLAPPED lpOverlapped)
413 {
414     BOOL retv = TRUE;
415
416     switch (dwIoControlCode)
417     {
418     case 5:
419         if (lpvOutBuffer && (cbOutBuffer>=4))
420             *(DWORD*)lpvOutBuffer = GetTickCount();
421
422         if (lpcbBytesReturned)
423             *lpcbBytesReturned = 4;
424
425         break;
426
427     default:
428         FIXME( "Control %ld not implemented\n", dwIoControlCode);
429         retv = FALSE;
430         break;
431     }
432
433     return retv;
434 }
435
436 /***********************************************************************
437  *           DeviceIo_IFSMgr
438  * NOTES
439  *   These ioctls are used by 'MSNET32.DLL'.
440  *
441  *   I have been unable to uncover any documentation about the ioctls so
442  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
443  *   based on reasonable guesses on information found in the Windows 95 DDK.
444  *
445  */
446
447 /*
448  * IFSMgr DeviceIO service
449  */
450
451 #define IFS_IOCTL_21                100
452 #define IFS_IOCTL_2F                101
453 #define IFS_IOCTL_GET_RES           102
454 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
455
456 struct win32apireq {
457         unsigned long   ar_proid;
458         unsigned long   ar_eax;
459         unsigned long   ar_ebx;
460         unsigned long   ar_ecx;
461         unsigned long   ar_edx;
462         unsigned long   ar_esi;
463         unsigned long   ar_edi;
464         unsigned long   ar_ebp;
465         unsigned short  ar_error;
466         unsigned short  ar_pad;
467 };
468
469 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
470 {
471         memset(pCxt,0,sizeof(*pCxt));
472
473         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
474         pCxt->Eax = pIn->ar_eax;
475         pCxt->Ebx = pIn->ar_ebx;
476         pCxt->Ecx = pIn->ar_ecx;
477         pCxt->Edx = pIn->ar_edx;
478         pCxt->Esi = pIn->ar_esi;
479         pCxt->Edi = pIn->ar_edi;
480
481         /* FIXME: Only partial CONTEXT86_CONTROL */
482         pCxt->Ebp = pIn->ar_ebp;
483
484         /* FIXME: pIn->ar_proid ignored */
485         /* FIXME: pIn->ar_error ignored */
486         /* FIXME: pIn->ar_pad ignored */
487 }
488
489 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
490 {
491         memset(pOut,0,sizeof(struct win32apireq));
492
493         pOut->ar_eax = pCxt->Eax;
494         pOut->ar_ebx = pCxt->Ebx;
495         pOut->ar_ecx = pCxt->Ecx;
496         pOut->ar_edx = pCxt->Edx;
497         pOut->ar_esi = pCxt->Esi;
498         pOut->ar_edi = pCxt->Edi;
499
500         /* FIXME: Only partial CONTEXT86_CONTROL */
501         pOut->ar_ebp = pCxt->Ebp;
502
503         /* FIXME: pOut->ar_proid ignored */
504         /* FIXME: pOut->ar_error ignored */
505         /* FIXME: pOut->ar_pad ignored */
506 }
507
508 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
509                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
510                               LPDWORD lpcbBytesReturned,
511                               LPOVERLAPPED lpOverlapped)
512 {
513     BOOL retv = TRUE;
514         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
515                         dwIoControlCode,
516                         lpvInBuffer,cbInBuffer,
517                         lpvOutBuffer,cbOutBuffer,
518                         lpcbBytesReturned,
519                         lpOverlapped);
520
521     switch (dwIoControlCode)
522     {
523         case IFS_IOCTL_21:
524         case IFS_IOCTL_2F:{
525                 CONTEXT86 cxt;
526                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
527                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
528
529                 TRACE(
530                         "Control '%s': "
531                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
532                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
533                         "error=0x%04x, pad=0x%04x\n",
534                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
535                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
536                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
537                         pIn->ar_error, pIn->ar_pad
538                 );
539
540                 win32apieq_2_CONTEXT(pIn,&cxt);
541
542                 if(dwIoControlCode==IFS_IOCTL_21)
543                     INSTR_CallBuiltinHandler( &cxt, 0x21 );
544                 else
545                     INSTR_CallBuiltinHandler( &cxt, 0x2f );
546
547                 CONTEXT_2_win32apieq(&cxt,pOut);
548
549         retv = TRUE;
550         } break;
551         case IFS_IOCTL_GET_RES:{
552         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
553         retv = FALSE;
554         } break;
555         case IFS_IOCTL_GET_NETPRO_NAME_A:{
556         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
557         retv = FALSE;
558         } break;
559     default:
560         FIXME( "Control %ld not implemented\n", dwIoControlCode);
561         retv = FALSE;
562     }
563
564     return retv;
565 }
566
567 /***********************************************************************
568  *           DeviceIo_VCD
569  */
570 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
571                               LPVOID lpvInBuffer, DWORD cbInBuffer,
572                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
573                               LPDWORD lpcbBytesReturned,
574                               LPOVERLAPPED lpOverlapped)
575 {
576     BOOL retv = TRUE;
577
578     switch (dwIoControlCode)
579     {
580     case IOCTL_SERIAL_LSRMST_INSERT:
581     {
582         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
583         retv = FALSE;
584     }
585     break;
586
587     default:
588         FIXME( "Unknown Control %ld\n", dwIoControlCode);
589         retv = FALSE;
590         break;
591     }
592
593     return retv;
594 }
595
596
597 /***********************************************************************
598  *           DeviceIo_VWin32
599  */
600
601 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
602 {
603     memset( pCxt, 0, sizeof(*pCxt) );
604     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
605              will interpret 32-bit register contents as linear pointers */
606
607     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
608     pCxt->Eax = pIn->reg_EAX;
609     pCxt->Ebx = pIn->reg_EBX;
610     pCxt->Ecx = pIn->reg_ECX;
611     pCxt->Edx = pIn->reg_EDX;
612     pCxt->Esi = pIn->reg_ESI;
613     pCxt->Edi = pIn->reg_EDI;
614
615     /* FIXME: Only partial CONTEXT86_CONTROL */
616
617     pCxt->EFlags = pIn->reg_Flags & ~0x00020000; /* clear vm86 mode */
618 }
619
620 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
621 {
622     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
623
624     pOut->reg_EAX = pCxt->Eax;
625     pOut->reg_EBX = pCxt->Ebx;
626     pOut->reg_ECX = pCxt->Ecx;
627     pOut->reg_EDX = pCxt->Edx;
628     pOut->reg_ESI = pCxt->Esi;
629     pOut->reg_EDI = pCxt->Edi;
630
631     /* FIXME: Only partial CONTEXT86_CONTROL */
632     pOut->reg_Flags = pCxt->EFlags;
633 }
634
635 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
636 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
637 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
638 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
639 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
640 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
641
642 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
643 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
644 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
645 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
646
647 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
648
649 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
650                               LPVOID lpvInBuffer, DWORD cbInBuffer,
651                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
652                               LPDWORD lpcbBytesReturned,
653                               LPOVERLAPPED lpOverlapped)
654 {
655     BOOL retv = TRUE;
656
657     switch (dwIoControlCode)
658     {
659     case VWIN32_DIOC_DOS_IOCTL:
660     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
661     case VWIN32_DIOC_DOS_INT13:
662     case VWIN32_DIOC_DOS_INT25:
663     case VWIN32_DIOC_DOS_INT26:
664     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
665     case VWIN32_DIOC_DOS_DRIVEINFO:
666     {
667         CONTEXT86 cxt;
668         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
669         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
670         BYTE intnum = 0;
671
672         TRACE( "Control '%s': "
673                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
674                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
675                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
676                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
677                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
678                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
679                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
680                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
681
682         DIOCRegs_2_CONTEXT( pIn, &cxt );
683
684         switch (dwIoControlCode)
685         {
686         case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
687         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
688         case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
689             intnum = 0x21;
690             break;
691         case VWIN32_DIOC_DOS_INT13:
692             intnum = 0x13;
693             break;
694         case VWIN32_DIOC_DOS_INT25: 
695             intnum = 0x25;
696             break;
697         case VWIN32_DIOC_DOS_INT26:
698             intnum = 0x26;
699             break;
700         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
701             intnum = 0x31;
702             break;
703         }
704
705         INSTR_CallBuiltinHandler( &cxt, intnum );
706         CONTEXT_2_DIOCRegs( &cxt, pOut );
707     }
708     break;
709
710     case VWIN32_DIOC_SIMCTRLC:
711         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
712         retv = FALSE;
713         break;
714
715     default:
716         FIXME( "Unknown Control %ld\n", dwIoControlCode);
717         retv = FALSE;
718         break;
719     }
720
721     return retv;
722 }
723
724 /* this is the main multimedia device loader */
725 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
726                               LPVOID lpvInBuffer, DWORD cbInBuffer,
727                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
728                               LPDWORD lpcbBytesReturned,
729                               LPOVERLAPPED lpOverlapped)
730 {
731         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
732             dwIoControlCode,
733             lpvInBuffer,cbInBuffer,
734             lpvOutBuffer,cbOutBuffer,
735             lpcbBytesReturned,
736             lpOverlapped
737         );
738         switch (dwIoControlCode) {
739         case 5:
740                 /* Hmm. */
741                 *(DWORD*)lpvOutBuffer=0;
742                 *lpcbBytesReturned=4;
743                 return TRUE;
744         }
745         return FALSE;
746 }
747 /* this is used by some Origin games */
748 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
749                               LPVOID lpvInBuffer, DWORD cbInBuffer,
750                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
751                               LPDWORD lpcbBytesReturned,
752                               LPOVERLAPPED lpOverlapped)
753 {
754         switch (dwIoControlCode) {
755         case 1: /* version */
756                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
757                 break;
758         case 9: /* debug output */
759                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
760                 break;
761         default:
762                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
763                         dwIoControlCode,
764                         lpvInBuffer,cbInBuffer,
765                         lpvOutBuffer,cbOutBuffer,
766                         lpcbBytesReturned,
767                         lpOverlapped
768                 );
769                 break;
770         }
771         return TRUE;
772 }
773
774 /* pccard */
775 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
776                               LPVOID lpvInBuffer, DWORD cbInBuffer,
777                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
778                               LPDWORD lpcbBytesReturned,
779                               LPOVERLAPPED lpOverlapped)
780 {
781         switch (dwIoControlCode) {
782         case 0x0000: /* PCCARD_Get_Version */
783         case 0x0001: /* PCCARD_Card_Services */
784         default:
785                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
786                         dwIoControlCode,
787                         lpvInBuffer,cbInBuffer,
788                         lpvOutBuffer,cbOutBuffer,
789                         lpcbBytesReturned,
790                         lpOverlapped
791                 );
792                 break;
793         }
794         return FALSE;
795 }
796
797 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
798                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
799                               LPDWORD lpcbBytesReturned,
800                               LPOVERLAPPED lpOverlapped)
801 {
802     BOOL retv = TRUE;
803         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
804                         dwIoControlCode,
805                         lpvInBuffer,cbInBuffer,
806                         lpvOutBuffer,cbOutBuffer,
807                         lpcbBytesReturned,
808                         lpOverlapped);
809
810     return retv;
811 }
812
813 typedef UCHAR (WINAPI *NetbiosFunc)(LPVOID);
814
815 static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode,
816                               LPVOID lpvInBuffer, DWORD cbInBuffer,
817                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
818                               LPDWORD lpcbBytesReturned,
819                               LPOVERLAPPED lpOverlapped)
820 {
821     static HMODULE netapi;
822     static NetbiosFunc pNetbios;
823
824     if (dwIoControlCode != 256)
825     {
826         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
827                 dwIoControlCode,
828                 lpvInBuffer,cbInBuffer,
829                 lpvOutBuffer,cbOutBuffer,
830                 lpcbBytesReturned,
831                 lpOverlapped);
832     }
833     else
834     {
835         if (!pNetbios)
836         {
837             if (!netapi) netapi = LoadLibraryA("netapi32.dll");
838             if (netapi) pNetbios = (NetbiosFunc)GetProcAddress(netapi, "Netbios");
839         }
840         if (pNetbios)
841         {
842             pNetbios(lpvInBuffer);
843             return TRUE;
844         }
845     }
846     return FALSE;
847 }
848
849 static BOOL DeviceIo_DHCP(DWORD dwIoControlCode, LPVOID lpvInBuffer,
850                           DWORD cbInBuffer,
851                           LPVOID lpvOutBuffer, DWORD cbOutBuffer,
852                           LPDWORD lpcbBytesReturned,
853                           LPOVERLAPPED lpOverlapped)
854 {
855     DWORD error;
856
857     switch (dwIoControlCode) {
858     case 1:
859     {
860         /* since IpReleaseAddress/IpRenewAddress are not implemented, say there
861          * are no DHCP adapters
862          */
863         error = ERROR_FILE_NOT_FOUND;
864         break;
865     }
866
867     /* FIXME: don't know what this means */
868     case 5:
869         if (lpcbBytesReturned)
870             *lpcbBytesReturned = sizeof(DWORD);
871         if (lpvOutBuffer && cbOutBuffer >= 4)
872         {
873             *(LPDWORD)lpvOutBuffer = 0;
874             error = NO_ERROR;
875         }
876         else
877             error = ERROR_BUFFER_OVERFLOW;
878         break;
879
880     default:
881         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
882                 dwIoControlCode,
883                 lpvInBuffer,cbInBuffer,
884                 lpvOutBuffer,cbOutBuffer,
885                 lpcbBytesReturned,
886                 lpOverlapped);
887         error = ERROR_NOT_SUPPORTED;
888         break;
889     }
890     if (error)
891         SetLastError(error);
892     return error == NO_ERROR;
893 }
894
895 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PDWORD);
896 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO, PDWORD);
897
898 typedef struct _nbtInfo
899 {
900     DWORD ip;
901     DWORD winsPrimary;
902     DWORD winsSecondary;
903     DWORD dnsPrimary;
904     DWORD dnsSecondary;
905     DWORD unk0;
906 } nbtInfo;
907
908 #define MAX_NBT_ENTRIES 7
909
910 typedef struct _nbtTable
911 {
912     DWORD   numEntries;
913     nbtInfo table[MAX_NBT_ENTRIES];
914     UCHAR   pad[6];
915     WORD    nodeType;
916     WORD    scopeLen;
917     char    scope[254];
918 } nbtTable;
919
920 static BOOL DeviceIo_VNB(DWORD dwIoControlCode,
921                          LPVOID lpvInBuffer, DWORD cbInBuffer,
922                          LPVOID lpvOutBuffer, DWORD cbOutBuffer,
923                          LPDWORD lpcbBytesReturned,
924                          LPOVERLAPPED lpOverlapped)
925 {
926     static HMODULE iphlpapi;
927     static GetNetworkParamsFunc pGetNetworkParams;
928     static GetAdaptersInfoFunc pGetAdaptersInfo;
929     DWORD error;
930
931     switch (dwIoControlCode)
932     {
933         case 116:
934             if (lpcbBytesReturned)
935                 *lpcbBytesReturned = sizeof(nbtTable);
936             if (!lpvOutBuffer || cbOutBuffer < sizeof(nbtTable))
937                 error = ERROR_BUFFER_OVERFLOW;
938             else
939             {
940                 nbtTable *info = (nbtTable *)lpvOutBuffer;
941
942                 memset(info, 0, sizeof(nbtTable));
943                 if (!iphlpapi)
944                 {
945                     iphlpapi = LoadLibraryA("iphlpapi.dll");
946                     pGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(iphlpapi,"GetNetworkParams");
947                     pGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(iphlpapi, "GetAdaptersInfo");
948                 }
949                 if (iphlpapi)
950                 {
951                     DWORD size = 0;
952
953                     error = pGetNetworkParams(NULL, &size);
954                     if (ERROR_BUFFER_OVERFLOW == error)
955                     {
956                         PFIXED_INFO fixedInfo = (PFIXED_INFO)HeapAlloc(
957                          GetProcessHeap(), 0, size);
958
959                         error = pGetNetworkParams(fixedInfo, &size);
960                         if (NO_ERROR == error)
961                         {
962                             info->nodeType = (WORD)fixedInfo->NodeType;
963                             info->scopeLen = min(strlen(fixedInfo->ScopeId) + 1,
964                              sizeof(info->scope) - 2);
965                             memcpy(info->scope + 1, fixedInfo->ScopeId,
966                              info->scopeLen);
967                             info->scope[info->scopeLen + 1] = '\0';
968                             {
969                                 /* convert into L2-encoded version */
970                                 char *ptr, *lenPtr;
971
972                                 for (ptr = info->scope + 1; *ptr &&
973                                  ptr - info->scope < sizeof(info->scope); )
974                                 {
975                                     for (lenPtr = ptr - 1, *lenPtr = 0;
976                                      *ptr && *ptr != '.' &&
977                                      ptr - info->scope < sizeof(info->scope);
978                                      ptr++)
979                                         *lenPtr += 1;
980                                     ptr++;
981                                 }
982                             }
983                             /* could set DNS servers here too, but since
984                              * ipconfig.exe and winipcfg.exe read these from the
985                              * registry, there's no point */
986                         }
987                         if (fixedInfo)
988                             HeapFree(GetProcessHeap(), 0, fixedInfo);
989                     }
990                     size = 0;
991                     error = pGetAdaptersInfo(NULL, &size);
992                     if (ERROR_BUFFER_OVERFLOW == error)
993                     {
994                         PIP_ADAPTER_INFO adapterInfo = (PIP_ADAPTER_INFO)
995                          HeapAlloc(GetProcessHeap(), 0, size);
996
997                         error = pGetAdaptersInfo(adapterInfo, &size);
998                         if (NO_ERROR == error)
999                         {
1000                             PIP_ADAPTER_INFO ptr = adapterInfo;
1001
1002                             for (ptr = adapterInfo; ptr && info->numEntries <
1003                              MAX_NBT_ENTRIES; ptr = ptr->Next)
1004                             {
1005                                 unsigned long addr;
1006
1007                                 addr = inet_addr(
1008                                  ptr->IpAddressList.IpAddress.String);
1009                                 if (addr != 0 && addr != INADDR_NONE)
1010                                     info->table[info->numEntries].ip =
1011                                      ntohl(addr);
1012                                 addr = inet_addr(
1013                                  ptr->PrimaryWinsServer.IpAddress.String);
1014                                 if (addr != 0 && addr != INADDR_NONE)
1015                                     info->table[info->numEntries].winsPrimary
1016                                      = ntohl(addr);
1017                                 addr = inet_addr(
1018                                  ptr->SecondaryWinsServer.IpAddress.String);
1019                                 if (addr != 0 && addr != INADDR_NONE)
1020                                     info->table[info->numEntries].winsSecondary
1021                                      = ntohl(addr);
1022                                 info->numEntries++;
1023                             }
1024                         }
1025                         if (adapterInfo)
1026                             HeapFree(GetProcessHeap(), 0, adapterInfo);
1027                     }
1028                 }
1029                 else
1030                     error = GetLastError();
1031             }
1032             break;
1033
1034         case 119:
1035             /* nbtstat.exe uses this, but the return seems to be a bunch of
1036              * pointers, so it's not so easy to reverse engineer.  Fall through
1037              * to unimplemented...
1038              */
1039         default:
1040             FIXME( "Unimplemented control %ld for VxD device VNB\n",
1041                                dwIoControlCode );
1042             error = ERROR_NOT_SUPPORTED;
1043             break;
1044     }
1045     if (error)
1046         SetLastError(error);
1047     return error == NO_ERROR;
1048 }