Fixed a race condition on RPC worker thread creation, and a typo.
[wine] / dlls / wsock32 / socket.c
1 /*
2  * WSOCK32 specific functions
3  *
4  * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21
22 /* FIXME: This hack is fixing a problem in WsControl.  When we call socket(),
23  * it will call into ws2_32's WSOCK32_socket (because of the redirection in
24  * our own .spec file).
25  * The problem is that socket() is predefined in a linux system header that
26  * we are including, which is different from the WINE definition.
27  * (cdecl vs. stdapi).  The result is stack corruption.
28  * Furthermore WsControl uses Unix macros and types. This forces us to include
29  * the Unix headers which then conflict with the winsock headers. This forces
30  * us to use USE_WS_PREFIX but then ioctlsocket is called WS_ioctlsocket,
31  * which causes link problems. The correct solution is to implement
32  * WsControl using calls to WSAIoctl. Then we should no longer need to use the
33  * Unix headers. This would also have the advantage of reducing code
34  * duplication.
35  * Until that happens we need this ugly hack.
36  */
37 #define USE_WS_PREFIX
38
39 #define socket  linux_socket
40 #define recv    linux_recv
41 /* */
42
43 #define setsockopt linux_setsockopt
44 #define getsockopt linux_getsockopt
45
46 #include "config.h"
47
48 #include <errno.h>
49 #include <string.h>
50 #include <ctype.h>
51 #include <fcntl.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #ifdef HAVE_UNISTD_H
55 # include <unistd.h>
56 #endif
57 #ifdef HAVE_SYS_IOCTL_H
58 # include <sys/ioctl.h>
59 #endif
60
61 #include <sys/types.h>
62 #ifdef HAVE_SYS_SOCKET_H
63 #include <sys/socket.h>
64 #endif
65 #ifdef HAVE_SYS_SOCKIO_H
66 # include <sys/sockio.h>
67 #endif
68 #ifdef HAVE_NET_IF_H
69 # include <net/if.h>
70 #endif
71
72 #include "windef.h"
73 #include "winbase.h"
74 #include "wine/debug.h"
75 #include "winsock2.h"
76 #include "winnt.h"
77 #include "wscontrol.h"
78
79 /* FIXME: The rest of the socket() cdecl<->stdapi stack corruption problem
80  * discussed above.
81  */
82 #undef socket
83 #undef recv
84 extern SOCKET WINAPI socket(INT af, INT type, INT protocol);
85 extern SOCKET WINAPI recv(SOCKET,char*,int,int);
86 /* Plus some missing prototypes, due to the WS_ prefixing */
87 extern int    WINAPI closesocket(SOCKET);
88 extern int    WINAPI ioctlsocket(SOCKET,long,u_long*);
89 /* */
90
91 /* for the get/setsockopt forwarders */
92 #undef setsockopt
93 #undef getsockopt
94 extern int WINAPI setsockopt(SOCKET s, INT level, INT optname ,char* optval, INT optlen);
95 extern int WINAPI getsockopt(SOCKET s, INT level, INT optname ,char* optval, INT* optlen);
96
97 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
98
99 /* internal remapper function for the IP_ constants */
100 static INT _remap_optname(INT level, INT optname)
101 {
102   TRACE("level=%d, optname=%d\n", level, optname);
103   if (level == WS_IPPROTO_IP) {
104     switch (optname) {       /***** from value *****/
105       case 2: return 9;      /* IP_MULTICAST_IF    */
106       case 3: return 10;     /* IP_MULTICAST_TTL   */
107       case 4: return 11;     /* IP_MULTICAST_LOOP  */
108       case 5: return 12;     /* IP_ADD_MEMBERSHIP  */
109       case 6: return 13;     /* IP_DROP_MEMBERSHIP */
110       case 7: return 4;      /* IP_TTL             */
111       case 8: return 3;      /* IP_TOS             */
112       case 9: return 14;     /* IP_DONTFRAGMENT    */
113       default: FIXME("Unknown optname %d, can't remap!\n", optname); return optname; 
114     }
115   } else {
116     /* don't need to do anything */
117     return optname;
118   }
119 }
120
121 /***********************************************************************
122  *              setsockopt              (WSOCK32.21)
123  *
124  * We have these forwarders because, for reasons unknown to us mere mortals,
125  * the values of the IP_ constants changed between winsock.h and winsock2.h.
126  * So, we need to remap them here.
127  */
128 INT WINAPI WS1_setsockopt(SOCKET s, INT level, INT optname, char *optval, INT optlen)
129 {
130   return setsockopt(s, level, _remap_optname(level, optname), optval, optlen);
131 }
132
133 /***********************************************************************
134  *              getsockopt              (WSOCK32.7)
135  */
136 INT WINAPI WS1_getsockopt(SOCKET s, INT level, INT optname, char *optval, INT *optlen)
137 {
138   return getsockopt(s, level, _remap_optname(level, optname), optval, optlen);
139 }
140
141 /***********************************************************************
142  *              WsControl (WSOCK32.1001)
143  *
144  * WsControl seems to be an undocumented Win95 function. A lot of
145  * discussion about WsControl can be found on the net, e.g.
146  * Subject:      Re: WSOCK32.DLL WsControl Exported Function
147  * From:         "Peter Rindfuss" <rindfuss-s@medea.wz-berlin.de>
148  * Date:         1997/08/17
149  *
150  * WSCNTL_TCPIP_QUERY_INFO option is partially implemeted based
151  * on observing the behaviour of WsControl with an app in
152  * Windows 98.  It is not fully implemented, and there could
153  * be (are?) errors due to incorrect assumptions made.
154  *
155  *
156  * WsControl returns WSCTL_SUCCESS on success.
157  * STATUS_BUFFER_TOO_SMALL is returned if the output buffer length
158  * (*pcbResponseInfoLen) is too small, otherwise errors return -1.
159  *
160  * It doesn't seem to generate errors that can be retrieved by
161  * WSAGetLastError().
162  *
163  */
164
165 DWORD WINAPI WsControl(DWORD protocoll,
166                        DWORD action,
167                        LPVOID pRequestInfo,
168                        LPDWORD pcbRequestInfoLen,
169                        LPVOID pResponseInfo,
170                        LPDWORD pcbResponseInfoLen)
171 {
172    /* Get the command structure into a pointer we can use,
173       rather than void */
174    TDIObjectID *pcommand = (TDIObjectID *)pRequestInfo;
175
176    TRACE ("   WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n",
177           pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
178           pcommand->toi_class, pcommand->toi_type );
179
180
181
182    switch (action)
183    {
184       case WSCNTL_TCPIP_QUERY_INFO:
185       {
186          switch (pcommand->toi_id)
187          {
188             /*
189                ENTITY_LIST_ID seems to get number of adapters in the system.
190                (almost like an index to be used when calling other WsControl options)
191             */
192             case ENTITY_LIST_ID:
193             {
194                TDIEntityID *baseptr = pResponseInfo;
195                int numInt = 0, i;
196
197                if (pcommand->toi_class != INFO_CLASS_GENERIC &&
198                    pcommand->toi_type != INFO_TYPE_PROVIDER)
199                {
200                   FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
201                        pcommand->toi_class, pcommand->toi_type);
202                   return (WSAEOPNOTSUPP);
203                }
204
205                numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
206                if (numInt < 0)
207                {
208                   ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
209                   return (-1);
210                }
211
212                if (*pcbResponseInfoLen < sizeof(TDIEntityID)*(numInt*2) )
213                {
214                   return (STATUS_BUFFER_TOO_SMALL);
215                }
216
217                /* 0 it out first */
218                memset(baseptr, 0, sizeof(TDIEntityID)*(numInt*2));
219
220                for (i=0; i<numInt; i++)
221                {
222                   /* tei_instance is an network interface identifier.
223                      I'm not quite sure what the difference is between tei_entity values of
224                      CL_NL_ENTITY and IF_ENTITY */
225                   baseptr->tei_entity = CL_NL_ENTITY;  baseptr->tei_instance = i; baseptr++;
226                   baseptr->tei_entity = IF_ENTITY;     baseptr->tei_instance = i; baseptr++;
227                }
228
229                /* Calculate size of out buffer */
230                *pcbResponseInfoLen = sizeof(TDIEntityID)*(numInt*2);
231
232                break;
233             }
234
235
236             /* ENTITY_TYPE_ID is used to obtain simple information about a
237                network card, such as MAC Address, description, interface type,
238                number of network addresses, etc. */
239             case ENTITY_TYPE_ID:  /* ALSO: IP_MIB_STATS_ID */
240             {
241                if (pcommand->toi_class == INFO_CLASS_GENERIC && pcommand->toi_type == INFO_TYPE_PROVIDER)
242                {
243                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
244                   {
245                      * ((ULONG *)pResponseInfo) = IF_MIB;
246
247                      /* Calculate size of out buffer */
248                      *pcbResponseInfoLen = sizeof (ULONG);
249
250                   }
251                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
252                   {
253                      * ((ULONG *)pResponseInfo) = CL_NL_IP;
254
255                      /* Calculate size of out buffer */
256                      *pcbResponseInfoLen = sizeof (ULONG);
257                   }
258                }
259                else if (pcommand->toi_class == INFO_CLASS_PROTOCOL &&
260                         pcommand->toi_type == INFO_TYPE_PROVIDER)
261                {
262                   if (pcommand->toi_entity.tei_entity == IF_ENTITY)
263                   {
264                      /* In this case, we are requesting specific information about a
265                         a particular network adapter. (MAC Address, speed, data transmitted/received,
266                         etc.)
267                      */
268                      IFEntry *IntInfo = (IFEntry *) pResponseInfo;
269                      char ifName[512];
270 #if defined(SIOCGIFHWADDR) || defined(SIOCGENADDR)
271                      struct ifreq ifInfo;
272 #endif
273                      SOCKET sock;
274
275
276                      if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
277                      {
278                         ERR ("Unable to parse /proc filesystem!\n");
279                         return (-1);
280                      }
281
282                      /* Get a socket so that we can use ioctl */
283                      if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
284                      {
285                         ERR ("Error creating socket!\n");
286                         return (-1);
287                      }
288
289                      /* 0 out return structure first */
290                      memset (IntInfo, 0, sizeof(IFEntry));
291
292                      /* Interface ID */
293                      IntInfo->if_index = pcommand->toi_entity.tei_instance;
294
295                      /* MAC Address - Let's try to do this in a cross-platform way... */
296 #if defined(SIOCGIFHWADDR) /* Linux */
297                         strcpy(ifInfo.ifr_name, ifName);
298                         if (ioctlsocket(sock, SIOCGIFHWADDR, (ULONG*)&ifInfo) < 0)
299                         {
300                            ERR ("Error obtaining MAC Address!\n");
301                            closesocket(sock);
302                            return (-1);
303                         }
304                         else
305                         {
306                            /* FIXME: Is it correct to assume size of 6? */
307                            memcpy(IntInfo->if_physaddr, ifInfo.ifr_hwaddr.sa_data, 6);
308                            IntInfo->if_physaddrlen=6;
309                         }
310 #elif defined(SIOCGENADDR) /* Solaris */
311                         if (ioctlsocket(sock, SIOCGENADDR, (ULONG*)&ifInfo) < 0)
312                         {
313                            ERR ("Error obtaining MAC Address!\n");
314                            closesocket(sock);
315                            return (-1);
316                         }
317                         else
318                         {
319                            /* FIXME: Is it correct to assume size of 6? */
320                            memcpy(IntInfo->if_physaddr, ifInfo.ifr_enaddr, 6);
321                            IntInfo->if_physaddrlen=6;
322                         }
323 #else
324                         memset (IntInfo->if_physaddr, 0, 6);
325                         ERR ("Unable to determine MAC Address on your platform!\n");
326 #endif
327
328
329                      /* Interface name and length */
330                      strcpy (IntInfo->if_descr, ifName);
331                      IntInfo->if_descrlen= strlen (IntInfo->if_descr);
332
333                      /* Obtain bytes transmitted/received for interface */
334                      if ( (WSCNTL_GetTransRecvStat(pcommand->toi_entity.tei_instance,
335                            &IntInfo->if_inoctets, &IntInfo->if_outoctets)) < 0)
336                      {
337                         ERR ("Error obtaining transmit/receive stats for the network interface!\n");
338                         closesocket(sock);
339                         return (-1);
340                      }
341
342
343                      /* FIXME: How should the below be properly calculated? ******************/
344                      IntInfo->if_type =  0x6; /* Ethernet (?) */
345                      IntInfo->if_speed = 1000000; /* Speed of interface (bits per second?) */
346                      /************************************************************************/
347
348                      closesocket(sock);
349                      *pcbResponseInfoLen = sizeof (IFEntry) + IntInfo->if_descrlen;
350                   }
351                   else if (pcommand->toi_entity.tei_entity == CL_NL_ENTITY)
352                   {
353                      IPSNMPInfo *infoStruc = (IPSNMPInfo *) pResponseInfo;
354                      int numInt, numRoutes;
355
356                      /* This case is used to obtain general statistics about the
357                         network */
358
359                      if (*pcbResponseInfoLen < sizeof(IPSNMPInfo) )
360                      {
361                         return (STATUS_BUFFER_TOO_SMALL);
362                      }
363                      else
364                      {
365                         /* 0 it out first */
366                         memset(infoStruc, 0, sizeof(IPSNMPInfo));
367
368                         /* Get the number of interfaces */
369                         numInt = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
370                         if (numInt < 0)
371                         {
372                            ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
373                            return (-1);
374                         }
375                         /* Get the number of routes */
376                         numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
377                         if (numRoutes < 0)
378                         {
379                            ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
380                            return (-1);
381                         }
382
383                         infoStruc->ipsi_numif           = numInt; /* # of interfaces */
384                         infoStruc->ipsi_numaddr         = numInt; /* # of addresses */
385                         infoStruc->ipsi_numroutes       = numRoutes; /* # of routes */
386
387                         /* FIXME: How should the below be properly calculated? ******************/
388                         infoStruc->ipsi_forwarding      = 0x0;
389                         infoStruc->ipsi_defaultttl      = 0x0;
390                         infoStruc->ipsi_inreceives      = 0x0;
391                         infoStruc->ipsi_inhdrerrors     = 0x0;
392                         infoStruc->ipsi_inaddrerrors    = 0x0;
393                         infoStruc->ipsi_forwdatagrams   = 0x0;
394                         infoStruc->ipsi_inunknownprotos = 0x0;
395                         infoStruc->ipsi_indiscards      = 0x0;
396                         infoStruc->ipsi_indelivers      = 0x0;
397                         infoStruc->ipsi_outrequests     = 0x0;
398                         infoStruc->ipsi_routingdiscards = 0x0;
399                         infoStruc->ipsi_outdiscards     = 0x0;
400                         infoStruc->ipsi_outnoroutes     = 0x0;
401                         infoStruc->ipsi_reasmtimeout    = 0x0;
402                         infoStruc->ipsi_reasmreqds      = 0x0;
403                         infoStruc->ipsi_reasmoks        = 0x0;
404                         infoStruc->ipsi_reasmfails      = 0x0;
405                         infoStruc->ipsi_fragoks         = 0x0;
406                         infoStruc->ipsi_fragfails       = 0x0;
407                         infoStruc->ipsi_fragcreates     = 0x0;
408                         /************************************************************************/
409
410                         /* Calculate size of out buffer */
411                         *pcbResponseInfoLen = sizeof(IPSNMPInfo);
412                      }
413                   }
414                }
415                else
416                {
417                   FIXME ("Unexpected Option for ENTITY_TYPE_ID request -> toi_class=0x%lx, toi_type=0x%lx\n",
418                        pcommand->toi_class, pcommand->toi_type);
419
420                   return (WSAEOPNOTSUPP);
421                }
422
423                break;
424             }
425
426
427             /* IP_MIB_ADDRTABLE_ENTRY_ID is used to obtain more detailed information about a
428                particular network adapter */
429             case IP_MIB_ADDRTABLE_ENTRY_ID:
430             {
431                IPAddrEntry *baseIPInfo = (IPAddrEntry *) pResponseInfo;
432                char ifName[IFNAMSIZ+1];
433                struct ifreq ifInfo;
434                SOCKET sock;
435
436                if (*pcbResponseInfoLen < sizeof(IPAddrEntry))
437                {
438                   return (STATUS_BUFFER_TOO_SMALL);
439                }
440
441                if (!WSCNTL_GetInterfaceName(pcommand->toi_entity.tei_instance, ifName))
442                {
443                   ERR ("Unable to parse /proc filesystem!\n");
444                   return (-1);
445                }
446
447
448                /* Get a socket so we can use ioctl */
449                if ( (sock = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
450                {
451                   ERR ("Error creating socket!\n");
452                   return (-1);
453                }
454
455                /* 0 it out first */
456                memset(baseIPInfo, 0, sizeof(IPAddrEntry) );
457
458                /* Interface Id */
459                baseIPInfo->iae_index     = pcommand->toi_entity.tei_instance;
460
461                /* IP Address */
462                strcpy (ifInfo.ifr_name, ifName);
463                ifInfo.ifr_addr.sa_family = AF_INET;
464                if (ioctlsocket(sock, SIOCGIFADDR, (ULONG*)&ifInfo) < 0)
465                {
466                   baseIPInfo->iae_addr = 0x0;
467                }
468                else
469                {
470                   struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_addr;
471                   baseIPInfo->iae_addr = ipTemp->sin_addr.S_un.S_addr;
472                }
473
474                /* Broadcast Address */
475                strcpy (ifInfo.ifr_name, ifName);
476                if (ioctlsocket(sock, SIOCGIFBRDADDR, (ULONG *)&ifInfo) < 0)
477                {
478                   baseIPInfo->iae_bcastaddr = 0x0;
479                }
480                else
481                {
482                   struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_broadaddr;
483                   baseIPInfo->iae_bcastaddr = ipTemp->sin_addr.S_un.S_addr;
484                }
485
486                /* Subnet Mask */
487                strcpy(ifInfo.ifr_name, ifName);
488                if (ioctlsocket(sock, SIOCGIFNETMASK, (ULONG *)&ifInfo) < 0)
489                {
490                   baseIPInfo->iae_mask = 0x0;
491                }
492                else
493                {
494                   /* Trying to avoid some compile problems across platforms.
495                      (Linux, FreeBSD, Solaris...) */
496                   #ifndef ifr_netmask
497                      #ifndef ifr_addr
498                         baseIPInfo->iae_mask = 0;
499                         ERR ("Unable to determine Netmask on your platform!\n");
500                      #else
501                         struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_addr;
502                         baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
503                      #endif
504                   #else
505                      struct WS_sockaddr_in* ipTemp = (struct WS_sockaddr_in*)&ifInfo.ifr_netmask;
506                      baseIPInfo->iae_mask = ipTemp->sin_addr.S_un.S_addr;
507                   #endif
508                }
509
510                /* FIXME: How should the below be properly calculated? ******************/
511                baseIPInfo->iae_reasmsize = 0x0;
512                baseIPInfo->iae_context   = 0x0;
513                baseIPInfo->iae_pad       = 0x0;
514                /************************************************************************/
515
516                /* Calculate size of out buffer */
517                *pcbResponseInfoLen = sizeof(IPAddrEntry);
518                closesocket(sock);
519                break;
520             }
521
522
523             /* This call returns the routing table.
524              * No official documentation found, even the name of the command is unknown.
525              * Work is based on
526              * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html
527              * and testings done with winipcfg.exe, route.exe and ipconfig.exe.
528              * pcommand->toi_entity.tei_instance seems to be the interface number
529              * but route.exe outputs only the information for the last interface
530              * if only the routes for the pcommand->toi_entity.tei_instance
531              * interface are returned. */
532             case IP_MIB_ROUTETABLE_ENTRY_ID:    /* FIXME: not real name. Value is 0x101 */
533             {
534                 int numRoutes, foundRoutes;
535                 wscntl_routeentry *routeTable, *routePtr;       /* route table */
536
537                 IPRouteEntry *winRouteTable  = (IPRouteEntry *) pResponseInfo;
538
539                 /* Get the number of routes */
540                 numRoutes = WSCNTL_GetEntryCount(WSCNTL_COUNT_ROUTES);
541                 if (numRoutes < 0)
542                 {
543                     ERR ("Unable to open /proc filesystem to determine number of network routes!\n");
544                     return (-1);
545                 }
546
547                 if (*pcbResponseInfoLen < (sizeof(IPRouteEntry) * numRoutes))
548                 {
549                     return (STATUS_BUFFER_TOO_SMALL);
550                 }
551
552                 /* malloc space for the routeTable */
553                 routeTable = (wscntl_routeentry *) malloc(sizeof(wscntl_routeentry) * numRoutes);
554                 if (!routeTable)
555                 {
556                     ERR ("couldn't malloc space for routeTable!\n");
557                 }
558
559                 /* get the route table */
560                 foundRoutes = WSCNTL_GetRouteTable(numRoutes, routeTable);
561                 if (foundRoutes < 0)
562                 {
563                     ERR ("Unable to open /proc filesystem to parse the route entries!\n");
564                     free(routeTable);
565                     return -1;
566                 }
567                 routePtr = routeTable;
568
569                 /* first 0 out the output buffer */
570                 memset(winRouteTable, 0, *pcbResponseInfoLen);
571
572                 /* calculate the length of the data in the output buffer */
573                 *pcbResponseInfoLen = sizeof(IPRouteEntry) * foundRoutes;
574
575                 for ( ; foundRoutes > 0; foundRoutes--)
576                 {
577                     winRouteTable->ire_addr = routePtr->wre_dest;
578                     winRouteTable->ire_index = routePtr->wre_intf;
579                     winRouteTable->ire_metric = routePtr->wre_metric;
580                     /* winRouteTable->ire_option4 =
581                     winRouteTable->ire_option5 =
582                     winRouteTable->ire_option6 = */
583                     winRouteTable->ire_gw = routePtr->wre_gw;
584                     /* winRouteTable->ire_option8 =
585                     winRouteTable->ire_option9 =
586                     winRouteTable->ire_option10 = */
587                     winRouteTable->ire_mask = routePtr->wre_mask;
588                     /* winRouteTable->ire_option12 = */
589
590                     winRouteTable++;
591                     routePtr++;
592                 }
593
594                 free(routeTable);
595                 break;
596             }
597
598
599             default:
600             {
601                FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx, toi_type=0x%lx\n",
602                        pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance,
603                        pcommand->toi_class, pcommand->toi_type);
604
605                return (WSAEOPNOTSUPP);
606             }
607          }
608
609          break;
610       }
611
612       case WSCNTL_TCPIP_ICMP_ECHO:
613       {
614          unsigned int addr = *(unsigned int*)pRequestInfo;
615          #if 0
616             int timeout= *(unsigned int*)(inbuf+4);
617             short x1 = *(unsigned short*)(inbuf+8);
618             short sendbufsize = *(unsigned short*)(inbuf+10);
619             char x2 = *(unsigned char*)(inbuf+12);
620             char ttl = *(unsigned char*)(inbuf+13);
621             char service = *(unsigned char*)(inbuf+14);
622             char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/
623          #endif
624
625          FIXME("(ICMP_ECHO) to 0x%08x stub \n", addr);
626          break;
627       }
628
629       default:
630       {
631          FIXME("Protocoll Not Supported -> protocoll=0x%lx, action=0x%lx, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n",
632                protocoll, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen);
633
634          return (WSAEOPNOTSUPP);
635       }
636    }
637
638
639    return (WSCTL_SUCCESS);
640 }
641
642
643
644 /*
645   Helper function for WsControl - Get count of the number of interfaces
646   or routes by parsing /proc filesystem.
647 */
648 int WSCNTL_GetEntryCount(const int entrytype)
649 {
650    char *filename;
651    int  fd;
652    char buf[512];  /* Size optimized for a typical workstation */
653    char *ptr;
654    int  count;
655    int  chrread;
656
657
658    switch (entrytype)
659    {
660        case WSCNTL_COUNT_INTERFACES:
661        {
662            filename = PROCFS_NETDEV_FILE;
663            count = -2;  /* two haeder lines */
664            break;
665        };
666
667        case WSCNTL_COUNT_ROUTES:
668        {
669            filename = PROCFS_ROUTE_FILE;
670            count = -1;  /* one haeder line */
671            break;
672        };
673
674        default:
675        {
676            return -1;
677        };
678    }
679
680    /* open /proc filesystem file */
681    fd = open(filename, O_RDONLY);
682    if (fd < 0) {
683        return -1;
684    }
685
686    /* read the file and count the EOL's */
687    while ((chrread = read(fd, buf, sizeof(buf))) != 0)
688    {
689        ptr = buf;
690        if (chrread < 0)
691        {
692            if (errno == EINTR)
693            {
694                continue;        /* read interupted by a signal, try to read again */
695            }
696            else
697            {
698                close(fd);
699                return -1;
700            }
701        }
702        while ((ptr = memchr(ptr, '\n', chrread - (int) (ptr -  buf))) > 0)
703        {
704            count++;
705            ptr++;
706        }
707    }
708
709    close(fd);
710    return count;
711 }
712
713
714 /*
715    Helper function for WsControl - Get name of device from interface number
716    by parsing /proc filesystem.
717 */
718 int WSCNTL_GetInterfaceName(int intNumber, char *intName)
719 {
720    FILE *procfs;
721    char buf[512]; /* Size doesn't matter, something big */
722    int  i;
723
724    /* Open /proc filesystem file for network devices */
725    procfs = fopen(PROCFS_NETDEV_FILE, "r");
726    if (!procfs)
727    {
728       /* If we can't open the file, return an error */
729       return (-1);
730    }
731
732    /* Omit first two lines, they are only headers */
733    fgets(buf, sizeof(buf), procfs);
734    fgets(buf, sizeof(buf), procfs);
735
736    for (i=0; i<intNumber; i++)
737    {
738       /* Skip the lines that don't interest us. */
739       fgets(buf, sizeof(buf), procfs);
740    }
741    fgets(buf, sizeof(buf), procfs); /* This is the line we want */
742
743
744    /* Parse out the line, grabbing only the name of the device
745       to the intName variable
746
747       The Line comes in like this: (we only care about the device name)
748       lo:   21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
749    */
750    i=0;
751    while (isspace(buf[i])) /* Skip initial space(s) */
752    {
753       i++;
754    }
755
756    while (buf[i])
757    {
758       if (isspace(buf[i]))
759       {
760          break;
761       }
762
763       if (buf[i] == ':')  /* FIXME: Not sure if this block (alias detection) works properly */
764       {
765          /* This interface could be an alias... */
766          int hold = i;
767          char *dotname = intName;
768          *intName++ = buf[i++];
769
770          while (isdigit(buf[i]))
771          {
772             *intName++ = buf[i++];
773          }
774
775          if (buf[i] != ':')
776          {
777             /* ... It wasn't, so back up */
778             i = hold;
779             intName = dotname;
780          }
781
782          if (buf[i] == '\0')
783          {
784             fclose(procfs);
785             return(FALSE);
786          }
787
788          i++;
789          break;
790       }
791
792       *intName++ = buf[i++];
793    }
794    *intName++ = '\0';
795
796    fclose(procfs);
797    return(TRUE);
798 }
799
800
801 /*
802    Helper function for WsControl - This function returns the bytes (octets) transmitted
803    and received for the supplied interface number from the /proc fs.
804 */
805 int WSCNTL_GetTransRecvStat(int intNumber, unsigned long *transBytes, unsigned long *recvBytes)
806 {
807    FILE *procfs;
808    char buf[512], result[512]; /* Size doesn't matter, something big */
809    int  i, bufPos, resultPos;
810
811    /* Open /proc filesystem file for network devices */
812    procfs = fopen(PROCFS_NETDEV_FILE, "r");
813    if (!procfs)
814    {
815       /* If we can't open the file, return an error */
816       return (-1);
817    }
818
819    /* Omit first two lines, they are only headers */
820    fgets(buf, sizeof(buf), procfs);
821    fgets(buf, sizeof(buf), procfs);
822
823    for (i=0; i<intNumber; i++)
824    {
825       /* Skip the lines that don't interest us. */
826       fgets(buf, sizeof(buf), procfs);
827    }
828    fgets(buf, sizeof(buf), procfs); /* This is the line we want */
829
830
831
832    /* Parse out the line, grabbing the number of bytes transmitted
833       and received on the interface.
834
835       The Line comes in like this: (we care about columns 2 and 10)
836       lo:   21970 377 0 0 0 0 0 0 21970 377 0 0 0 0 0 0
837    */
838
839    /* Start at character 0 in the buffer */
840    bufPos=0;
841
842    /* Skip initial space(s) */
843    while (isspace(buf[bufPos]))
844       bufPos++;
845
846
847    /* Skip the name and its trailing spaces (if any) */
848    while (buf[bufPos])
849    {
850       if (isspace(buf[bufPos]))
851          break;
852
853       if (buf[bufPos] == ':') /* Could be an alias */
854       {
855          int hold = bufPos;
856
857          while(isdigit (buf[bufPos]))
858             bufPos++;
859          if (buf[bufPos] != ':')
860             bufPos = hold;
861          if (buf[bufPos] == '\0')
862          {
863             fclose(procfs);
864             return(FALSE);
865          }
866
867          bufPos++;
868          break;
869       }
870
871       bufPos++;
872    }
873    while (isspace(buf[bufPos]))
874       bufPos++;
875
876
877    /* This column (#2) is the number of bytes received. */
878    resultPos = 0;
879    while (!isspace(buf[bufPos]))
880    {
881       result[resultPos] = buf[bufPos];
882       result[resultPos+1]='\0';
883       resultPos++; bufPos++;
884    }
885    *recvBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
886
887
888    /* Skip columns #3 to #9 (Don't need them) */
889    for  (i=0; i<7; i++)
890    {
891       while (isspace(buf[bufPos]))
892          bufPos++;
893       while (!isspace(buf[bufPos]))
894          bufPos++;
895    }
896
897
898    /* This column (#10) is the number of bytes transmitted */
899    while (isspace(buf[bufPos]))
900        bufPos++;
901
902    resultPos = 0;
903    while (!isspace(buf[bufPos]))
904    {
905       result[resultPos] = buf[bufPos];
906       result[resultPos+1]='\0';
907       resultPos++; bufPos++;
908    }
909    *transBytes = strtoul (result, NULL, 10); /* convert string to unsigned long, using base 10 */
910
911
912    fclose(procfs);
913    return(TRUE);
914 }
915
916
917 /* Parse the procfs route file and put the datas into routeTable.
918  * Return value is the number of found routes */
919 int WSCNTL_GetRouteTable(int numRoutes, wscntl_routeentry *routeTable)
920 {
921     int nrIntf;         /* total number of interfaces */
922     char buf[256];      /* temporary buffer */
923     char *ptr;          /* pointer to temporary buffer */
924     FILE *file;         /* file handle for procfs route file */
925     int foundRoutes = 0;        /* number of found routes */
926     typedef struct interface_t {
927         char intfName[IFNAMSIZ+1];      /* the name of the interface */
928         int intfNameLen;        /* length of interface name */
929     } interface_t;
930     interface_t *interface;
931     int intfNr;         /* the interface number */
932
933     wscntl_routeentry *routePtr = routeTable;
934
935     /* get the number of interfaces */
936     nrIntf = WSCNTL_GetEntryCount(WSCNTL_COUNT_INTERFACES);
937     if (nrIntf < 0)
938     {
939         ERR ("Unable to open /proc filesystem to determine number of network interfaces!\n");
940         return (-1);
941     }
942
943     /* malloc space for the interface struct array */
944     interface = (interface_t *) malloc(sizeof(interface_t) * nrIntf);
945     if (!routeTable)
946     {
947         ERR ("couldn't malloc space for interface!\n");
948     }
949
950     for (intfNr = 0; intfNr < nrIntf; intfNr++) {
951         if (WSCNTL_GetInterfaceName(intfNr, interface[intfNr].intfName) < 0)
952         {
953             ERR ("Unable to open /proc filesystem to determine the name of network interfaces!\n");
954             free(interface);
955             return (-1);
956         }
957         interface[intfNr].intfNameLen = strlen(interface[intfNr].intfName);
958     }
959
960     /* Open /proc filesystem file for routes */
961     file = fopen(PROCFS_ROUTE_FILE, "r");
962     if (!file)
963     {
964         /* If we can't open the file, return an error */
965         free(interface);
966         return (-1);
967     }
968
969     /* skip the header line */
970     fgets(buf, sizeof(buf), file);
971
972     /* parse the rest of the file and put the matching entries into routeTable.
973        Format of procfs route entry:
974        Iface Destination Gateway Flags RefCnt Use Metric Mask  MTU Window IRTT
975        lo 0000007F 00000000 0001 0 0 0 000000FF 0 0 0
976     */
977     while (fgets(buf, sizeof(buf), file)) {
978         intfNr = 0;
979         /* find the interface of the route */
980         while ((strncmp(buf, interface[intfNr].intfName, interface[intfNr].intfNameLen) != 0)
981                 && (intfNr < nrIntf))
982         {
983             intfNr++;
984         }
985         if (intfNr < nrIntf) {
986             foundRoutes++;
987             if (foundRoutes > numRoutes) {
988                 /* output buffer is to small */
989                 ERR("buffer to small to fit all routes found into it!\n");
990                 free(interface);
991                 fclose(file);
992                 return -1;
993             }
994             ptr = buf;
995             ptr += interface[intfNr].intfNameLen;
996             routePtr->wre_intf = intfNr;
997             routePtr->wre_dest = strtoul(ptr, &ptr, 16);        /* destination */
998             routePtr->wre_gw = strtoul(ptr, &ptr, 16);  /* gateway */
999             strtoul(ptr, &ptr, 16);     /* Flags; unused */
1000             strtoul(ptr, &ptr, 16);     /* RefCnt; unused */
1001             strtoul(ptr, &ptr, 16);     /* Use; unused */
1002             routePtr->wre_metric = strtoul(ptr, &ptr, 16);      /* metric */
1003             routePtr->wre_mask = strtoul(ptr, &ptr, 16);        /* mask */
1004             /* strtoul(ptr, &ptr, 16);  MTU; unused */
1005             /* strtoul(ptr, &ptr, 16);  Window; unused */
1006             /* strtoul(ptr, &ptr, 16);  IRTT; unused */
1007
1008             routePtr++;
1009         }
1010         else
1011         {
1012             /* this should never happen */
1013             WARN("Skipping route with unknown interface\n");
1014         }
1015     }
1016
1017     free(interface);
1018     fclose(file);
1019     return foundRoutes;
1020 }
1021
1022
1023 /***********************************************************************
1024  *              WSARecvEx                       (WSOCK32.1107)
1025  *
1026  * WSARecvEx is a Microsoft specific extension to winsock that is identical to recv
1027  * except that has an in/out argument call flags that has the value MSG_PARTIAL ored
1028  * into the flags parameter when a partial packet is read. This only applies to
1029  * sockets using the datagram protocol. This method does not seem to be implemented
1030  * correctly by microsoft as the winsock implementation does not set the MSG_PARTIAL
1031  * flag when a fragmented packet arrives.
1032  */
1033 INT WINAPI WSARecvEx(SOCKET s, char *buf, INT len, INT *flags)
1034 {
1035     FIXME("(WSARecvEx) partial packet return value not set \n");
1036     return recv(s, buf, len, *flags);
1037 }
1038
1039
1040 /***********************************************************************
1041  *       s_perror         (WSOCK32.1108)
1042  */
1043 void WINAPI s_perror(LPCSTR message)
1044 {
1045     FIXME("(%s): stub\n",message);
1046     return;
1047 }