1 /*
2  * ethsock.cxx
3  *
4  * Direct Ethernet socket implementation.
5  *
6  * Portable Windows Library
7  *
8  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
9  *
10  * The contents of this file are subject to the Mozilla Public License
11  * Version 1.0 (the "License"); you may not use this file except in
12  * compliance with the License. You may obtain a copy of the License at
13  * http://www.mozilla.org/MPL/
14  *
15  * Software distributed under the License is distributed on an "AS IS"
16  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17  * the License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * The Original Code is Portable Windows Library.
21  *
22  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23  *
24  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25  * All Rights Reserved.
26  *
27  * Contributor(s): ______________________________________.
28  *
29  * $Revision: 25062 $
30  * $Author: rjongbloed $
31  * $Date: 2011-01-13 22:14:36 -0600 (Thu, 13 Jan 2011) $
32  */
33 
34 #include <ptlib.h>
35 #include <ptlib/sockets.h>
36 
37 #include <iphlpapi.h>
38 #ifdef _MSC_VER
39   #pragma comment(lib, "iphlpapi.lib")
40 #endif
41 
42 
43 ///////////////////////////////////////////////////////////////////////////////
44 // Stuff from ndis.h
45 
46 #define OID_802_3_PERMANENT_ADDRESS         0x01010101
47 #define OID_802_3_CURRENT_ADDRESS           0x01010102
48 
49 #define OID_GEN_DRIVER_VERSION              0x00010110
50 #define OID_GEN_CURRENT_PACKET_FILTER       0x0001010E
51 #define OID_GEN_MEDIA_SUPPORTED             0x00010103
52 
53 #if (WINVER <= 0x502)  // These are defined in Vista SDK
54 
55 	#define NDIS_PACKET_TYPE_DIRECTED           0x0001
56 	#define NDIS_PACKET_TYPE_MULTICAST          0x0002
57 	#define NDIS_PACKET_TYPE_ALL_MULTICAST      0x0004
58 	#define NDIS_PACKET_TYPE_BROADCAST          0x0008
59 	#define NDIS_PACKET_TYPE_PROMISCUOUS        0x0020
60 
61 	typedef enum _NDIS_MEDIUM {
62 		NdisMedium802_3,
63 		NdisMedium802_5,
64 		NdisMediumFddi,
65 		NdisMediumWan,
66 		NdisMediumLocalTalk,
67 		NdisMediumDix,              // defined for convenience, not a real medium
68 		NdisMediumArcnetRaw,
69 		NdisMediumArcnet878_2
70 	} NDIS_MEDIUM, *PNDIS_MEDIUM;
71 #endif
72 
73 ///////////////////////////////////////////////////////////////////////////////
74 
75 
76 #define USE_VPACKET
77 #include <ptlib/msos/ptlib/epacket.h>
78 
79 #define IPv6_ENABLED (P_HAS_IPV6 && (WINVER>=0x501))
80 
81 #if IPv6_ENABLED
82 #include <ptlib/msos/ptlib/addrv6.h>
83 #endif
84 
85 #ifdef USE_VPACKET
86 #define PACKET_SERVICE_NAME "Packet"
87 #define PACKET_VXD_NAME     "VPacket"
88 #else
89 #define PACKET_SERVICE_NAME "EPacket"
90 #define PACKET_VXD_NAME     "EPacket"
91 #endif
92 
93 #define SERVICES_REGISTRY_KEY "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\"
94 
95 
96 /////////////////////////////////////////////////////////////////////////////
97 
98 class PWin32OidBuffer
99 {
100   public:
101     PWin32OidBuffer(UINT oid, UINT len, const BYTE * data = NULL);
~PWin32OidBuffer()102     ~PWin32OidBuffer() { delete buffer; }
103 
operator void*()104     operator void *()         { return buffer; }
operator DWORD()105     operator DWORD ()         { return size; }
operator [](int i)106     DWORD operator [](int i)  { return buffer[i]; }
107 
108     void Move(BYTE * data, DWORD received);
109 
110   private:
111     DWORD * buffer;
112     UINT size;
113 };
114 
115 
116 ///////////////////////////////////////////////////////////////////////////////
117 
118 class PWin32PacketDriver
119 {
120   public:
121     static PWin32PacketDriver * Create();
122 
123     virtual ~PWin32PacketDriver();
124 
125     bool IsOpen() const;
126     void Close();
127     DWORD GetLastError() const;
128 
129     virtual bool EnumInterfaces(PINDEX idx, PString & name) = 0;
130     virtual bool BindInterface(const PString & interfaceName) = 0;
131 
132     virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask) = 0;
133 
134     virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap) = 0;
135     virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap) = 0;
136     bool CompleteIO(DWORD & received, PWin32Overlapped & overlap);
137 
138     bool IoControl(UINT func,
139                    const void * input, DWORD inSize,
140                    void * output, DWORD outSize,
141                    DWORD & received);
142 
143     PBoolean QueryOid(UINT oid, DWORD & data);
144     PBoolean QueryOid(UINT oid, UINT len, BYTE * data);
145     PBoolean SetOid(UINT oid, DWORD data);
146     PBoolean SetOid(UINT oid, UINT len, const BYTE * data);
GetQueryOidCommand(DWORD) const147     virtual UINT GetQueryOidCommand(DWORD /*oid*/) const { return IOCTL_EPACKET_QUERY_OID; }
148 
149   protected:
150     PWin32PacketDriver();
151 
152     DWORD dwError;
153     HANDLE hDriver;
154 };
155 
156 ///////////////////////////////////////////////////////////////////////////////
157 
158 #ifdef _WIN32_WCE
159 
160 class PWin32PacketCe : public PWin32PacketDriver
161 {
162   public:
163     PWin32PacketCe();
164 
165     virtual bool EnumInterfaces(PINDEX idx, PString & name);
166     virtual bool BindInterface(const PString & interfaceName);
167 
168     virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
169 
170     virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
171     virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
172 
173   protected:
174     PStringArray ipAddresses;
175     PStringArray netMasks;
176     PStringArray interfaces;
177 };
178 
179 #else // _WIN32_WCE
180 
181 /////////////////////////////////////////////////////////////////////////////
182 
183 class PWin32PacketVxD : public PWin32PacketDriver
184 {
185   public:
186     virtual bool EnumInterfaces(PINDEX idx, PString & name);
187     virtual bool BindInterface(const PString & interfaceName);
188 
189     virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
190 
191     virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
192     virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
193 
194 #ifdef USE_VPACKET
GetQueryOidCommand(DWORD oid) const195     virtual UINT GetQueryOidCommand(DWORD oid) const
196       { return oid >= OID_802_3_PERMANENT_ADDRESS ? IOCTL_EPACKET_QUERY_OID : IOCTL_EPACKET_STATISTICS; }
197 #endif
198 
199   protected:
200     PStringArray transportBinding;
201 };
202 
203 
204 ///////////////////////////////////////////////////////////////////////////////
205 
206 class PWin32PacketSYS : public PWin32PacketDriver
207 {
208   public:
209     PWin32PacketSYS();
210 
211     virtual bool EnumInterfaces(PINDEX idx, PString & name);
212     virtual bool BindInterface(const PString & interfaceName);
213 
214     virtual bool EnumIpAddress(PINDEX idx, PIPSocket::Address & addr, PIPSocket::Address & net_mask);
215 
216     virtual bool BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap);
217     virtual bool BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap);
218 
219   protected:
220     PString registryKey;
221 };
222 
223 
224 #endif // _WIN32_WCE
225 
226 
227 ///////////////////////////////////////////////////////////////////////////////
228 
229 class PWin32PacketBuffer : public PBYTEArray
230 {
231   PCLASSINFO(PWin32PacketBuffer, PBYTEArray)
232   public:
233     enum Statuses {
234       Uninitialised,
235       Progressing,
236       Completed
237     };
238 
239     PWin32PacketBuffer(PINDEX sz);
240 
241     PINDEX GetData(void * buf, PINDEX size);
242     PINDEX PutData(const void * buf, PINDEX length);
GetEvent() const243     HANDLE GetEvent() const { return overlap.hEvent; }
244 
245     bool ReadAsync(PWin32PacketDriver & pkt);
246     bool ReadComplete(PWin32PacketDriver & pkt);
247     bool WriteAsync(PWin32PacketDriver & pkt);
248     bool WriteComplete(PWin32PacketDriver & pkt);
249 
InProgress() const250     bool InProgress() const { return status == Progressing; }
IsCompleted() const251     bool IsCompleted() const { return status == Completed; }
252     bool IsType(WORD type) const;
253 
254   protected:
255     Statuses         status;
256     PWin32Overlapped overlap;
257     DWORD            count;
258 };
259 
260 
261 #define new PNEW
262 
263 
264 /////////////////////////////////////////////////////////////////////////////
265 
PWin32OidBuffer(UINT oid,UINT len,const BYTE * data)266 PWin32OidBuffer::PWin32OidBuffer(UINT oid, UINT len, const BYTE * data)
267 {
268   size = sizeof(DWORD)*2 + len;
269   buffer = new DWORD[(size+sizeof(DWORD)-1)/sizeof(DWORD)];
270 
271   buffer[0] = oid;
272   buffer[1] = len;
273   if (data != NULL)
274     memcpy(&buffer[2], data, len);
275 }
276 
277 
Move(BYTE * data,DWORD received)278 void PWin32OidBuffer::Move(BYTE * data, DWORD received)
279 {
280   memcpy(data, &buffer[2], received-sizeof(DWORD)*2);
281 }
282 
283 
284 ///////////////////////////////////////////////////////////////////////////////
285 
Create()286 PWin32PacketDriver * PWin32PacketDriver::Create()
287 {
288   OSVERSIONINFO info;
289   info.dwOSVersionInfoSize = sizeof(info);
290   GetVersionEx(&info);
291 #ifdef _WIN32_WCE
292   return new PWin32PacketCe;
293 #else // _WIN32_WCE
294   if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
295     return new PWin32PacketSYS;
296   else
297     return new PWin32PacketVxD;
298 #endif // _WIN32_WCE
299 }
300 
301 
PWin32PacketDriver()302 PWin32PacketDriver::PWin32PacketDriver()
303 {
304   hDriver = INVALID_HANDLE_VALUE;
305   dwError = ERROR_OPEN_FAILED;
306 }
307 
308 
~PWin32PacketDriver()309 PWin32PacketDriver::~PWin32PacketDriver()
310 {
311   Close();
312 }
313 
314 
Close()315 void PWin32PacketDriver::Close()
316 {
317   if (hDriver != INVALID_HANDLE_VALUE) {
318     CloseHandle(hDriver);
319     hDriver = INVALID_HANDLE_VALUE;
320   }
321 }
322 
323 
IsOpen() const324 bool PWin32PacketDriver::IsOpen() const
325 {
326   return hDriver != INVALID_HANDLE_VALUE;
327 }
328 
329 
GetLastError() const330 DWORD PWin32PacketDriver::GetLastError() const
331 {
332   return dwError;
333 }
334 
335 
IoControl(UINT func,const void * input,DWORD inSize,void * output,DWORD outSize,DWORD & received)336 bool PWin32PacketDriver::IoControl(UINT func,
337                               const void * input, DWORD inSize,
338                               void * output, DWORD outSize, DWORD & received)
339 {
340   PWin32Overlapped overlap;
341 
342   if (DeviceIoControl(hDriver, func,
343                       (LPVOID)input, inSize, output, outSize,
344                       &received, &overlap)) {
345     dwError = ERROR_SUCCESS;
346     return true;
347   }
348 
349   dwError = ::GetLastError();
350   if (dwError != ERROR_IO_PENDING)
351     return false;
352 
353   return CompleteIO(received, overlap);
354 }
355 
356 #ifdef _WIN32_WCE
CompleteIO(DWORD &,PWin32Overlapped &)357 bool PWin32PacketDriver::CompleteIO(DWORD &, PWin32Overlapped &)
358 {
359   return true;
360 }
361 #else
CompleteIO(DWORD & received,PWin32Overlapped & overlap)362 bool PWin32PacketDriver::CompleteIO(DWORD & received, PWin32Overlapped & overlap)
363 {
364   received = 0;
365   if (GetOverlappedResult(hDriver, &overlap, &received, true)) {
366     dwError = ERROR_SUCCESS;
367     return true;
368   }
369 
370   dwError = ::GetLastError();
371   return false;
372 }
373 #endif
374 
375 
QueryOid(UINT oid,UINT len,BYTE * data)376 PBoolean PWin32PacketDriver::QueryOid(UINT oid, UINT len, BYTE * data)
377 {
378   PWin32OidBuffer buf(oid, len);
379   DWORD rxsize = 0;
380   if (!IoControl(GetQueryOidCommand(oid), buf, buf, buf, buf, rxsize))
381     return PFalse;
382 
383   if (rxsize == 0)
384     return PFalse;
385 
386   buf.Move(data, rxsize);
387   return PTrue;
388 }
389 
390 
QueryOid(UINT oid,DWORD & data)391 PBoolean PWin32PacketDriver::QueryOid(UINT oid, DWORD & data)
392 {
393   DWORD oidData[3];
394   oidData[0] = oid;
395   oidData[1] = sizeof(data);
396   oidData[2] = 0x12345678;
397 
398   DWORD rxsize = 0;
399   if (!IoControl(GetQueryOidCommand(oid),
400                  oidData, sizeof(oidData),
401                  oidData, sizeof(oidData),
402                  rxsize))
403     return PFalse;
404 
405   if (rxsize == 0)
406     return PFalse;
407 
408   data = oidData[2];
409   return PTrue;
410 }
411 
412 
SetOid(UINT oid,UINT len,const BYTE * data)413 PBoolean PWin32PacketDriver::SetOid(UINT oid, UINT len, const BYTE * data)
414 {
415   DWORD rxsize = 0;
416   PWin32OidBuffer buf(oid, len, data);
417   return IoControl(IOCTL_EPACKET_SET_OID, buf, buf, buf, buf, rxsize);
418 }
419 
420 
SetOid(UINT oid,DWORD data)421 PBoolean PWin32PacketDriver::SetOid(UINT oid, DWORD data)
422 {
423   DWORD oidData[3];
424   oidData[0] = oid;
425   oidData[1] = sizeof(data);
426   oidData[2] = data;
427   DWORD rxsize;
428   return IoControl(IOCTL_EPACKET_SET_OID,
429                    oidData, sizeof(oidData), oidData, sizeof(oidData), rxsize);
430 }
431 
432 
433 ///////////////////////////////////////////////////////////////////////////////
434 
435 #ifdef _WIN32_WCE
436 
PWin32PacketCe()437 PWin32PacketCe::PWin32PacketCe()
438 {
439   PString str, driver, nameStr, keyStr, driverStr, miniportStr, linkageStr, routeStr, tcpipStr;
440 
441   static const PString ActiveDrivers = "HKEY_LOCAL_MACHINE\\Drivers\\Active";
442   static const PString CommBase = "HKEY_LOCAL_MACHINE\\Comm";
443 
444   // Collecting active drivers
445   RegistryKey registry(ActiveDrivers, RegistryKey::ReadOnly);
446   for (PINDEX idx = 0; registry.EnumKey(idx, str); idx++)
447   {
448     driver = ActiveDrivers + "\\" + str;
449     RegistryKey driverKey( driver, RegistryKey::ReadOnly );
450 
451     // Filter out non - NDS drivers
452     if (!driverKey.QueryValue( "Name", nameStr ) || nameStr.Find("NDS") == P_MAX_INDEX )
453       continue;
454 
455     // Active network driver found
456     //
457     // e.g. built-in driver has "Key" = Drivers\BuiltIn\NDIS
458     if( driverKey.QueryValue( "Key", keyStr ) )
459     {
460       if( P_MAX_INDEX != keyStr.Find("BuiltIn") )
461       {
462         // Built-in driver case
463         continue;
464       }
465       else
466       {
467         driverStr = "HKEY_LOCAL_MACHINE\\"+ keyStr;
468         RegistryKey ActiveDriverKey( driverStr, RegistryKey::ReadOnly );
469 
470         // Get miniport value
471         if( ActiveDriverKey.QueryValue( "Miniport", miniportStr ) )
472         {
473           // Get miniport linkage
474           //
475           // e.g. [HKEY_LOCAL_MACHINE\Comm\SOCKETLPE\Linkage]
476           linkageStr = CommBase + "\\" + miniportStr + "\\Linkage";
477 
478           RegistryKey LinkageKey( linkageStr, RegistryKey::ReadOnly );
479 
480           // Get route to real driver
481           if( LinkageKey.QueryValue( "Route", routeStr ) )
482           {
483             tcpipStr = CommBase + "\\" + routeStr + "\\Parms\\TcpIp";
484 
485             RegistryKey TcpIpKey( tcpipStr, RegistryKey::ReadOnly );
486 
487             DWORD dwDHCPEnabled = false;
488             TcpIpKey.QueryValue( "EnableDHCP", dwDHCPEnabled, true );
489 
490             /// Collect IP addresses and net masks
491             PString ipAddress, netMask;
492             if ( !dwDHCPEnabled )
493             {
494               if  (TcpIpKey.QueryValue( "IpAddress", ipAddress )
495                   && (ipAddress != "0.0.0.0") )
496               {
497                 interfaces[interfaces.GetSize()] = tcpipStr; // Registry key for the driver
498                 ipAddresses[ipAddresses.GetSize()] = ipAddress; // It's IP
499                 if( driverKey.QueryValue( "Subnetmask", netMask ) )
500                   netMasks[netMasks.GetSize()] = netMask; // It's mask
501                 else
502                   netMasks[netMasks.GetSize()] = "255.255.255.0";
503               }
504             }
505             else // DHCP enabled
506             if( TcpIpKey.QueryValue( "DhcpIpAddress", ipAddress )
507               && (ipAddress != "0.0.0.0") )
508             {
509               interfaces[interfaces.GetSize()] = str;
510               ipAddresses[ipAddresses.GetSize()] = ipAddress;
511               if( driverKey.QueryValue( "DhcpSubnetMask", netMask ) )
512                 netMasks[netMasks.GetSize()] = netMask;
513               else
514                 netMasks[netMasks.GetSize()] = "255.255.255.0";
515             }
516           }
517         }
518       }
519     }
520   }
521 }
522 
EnumInterfaces(PINDEX idx,PString & name)523 bool PWin32PacketCe::EnumInterfaces(PINDEX idx, PString & name)
524 {
525   if( idx >= interfaces.GetSize() )
526     return false;
527 
528   name = interfaces[idx];
529   return true;
530 }
531 
532 
BindInterface(const PString &)533 bool PWin32PacketCe::BindInterface(const PString &)
534 {
535   return true;
536 }
537 
538 
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)539 bool PWin32PacketCe::EnumIpAddress(PINDEX idx,
540                                     PIPSocket::Address & addr,
541                                     PIPSocket::Address & net_mask)
542 {
543   if( idx >= interfaces.GetSize() )
544     return false;
545 
546   addr = ipAddresses[idx];
547   net_mask = netMasks[idx];
548   return true;
549 }
550 
551 
BeginRead(void *,DWORD,DWORD &,PWin32Overlapped &)552 bool PWin32PacketCe::BeginRead(void *, DWORD, DWORD & , PWin32Overlapped &)
553 {
554   return true;
555 }
556 
557 
BeginWrite(const void *,DWORD,PWin32Overlapped &)558 bool PWin32PacketCe::BeginWrite(const void *, DWORD, PWin32Overlapped &)
559 {
560   return true;
561 }
562 
563 #else // _WIN32_WCE
564 
565 ///////////////////////////////////////////////////////////////////////////////
566 
EnumInterfaces(PINDEX idx,PString & name)567 bool PWin32PacketVxD::EnumInterfaces(PINDEX idx, PString & name)
568 {
569   static const PString RegBase = SERVICES_REGISTRY_KEY "Class\\Net";
570 
571   PString keyName;
572   RegistryKey registry(RegBase, RegistryKey::ReadOnly);
573   if (!registry.EnumKey(idx, keyName))
574     return false;
575 
576   PString description;
577   RegistryKey subkey(RegBase + "\\" + keyName, RegistryKey::ReadOnly);
578   if (subkey.QueryValue("DriverDesc", description))
579     name = keyName + ": " + description;
580   else
581     name = keyName;
582 
583   return true;
584 }
585 
586 
SearchRegistryKeys(const PString & key,const PString & variable,const PString & value)587 static PString SearchRegistryKeys(const PString & key,
588                                   const PString & variable,
589                                   const PString & value)
590 {
591   RegistryKey registry(key, RegistryKey::ReadOnly);
592 
593   PString str;
594   if (registry.QueryValue(variable, str) && (str *= value))
595     return key;
596 
597   for (PINDEX idx = 0; registry.EnumKey(idx, str); idx++) {
598     PString result = SearchRegistryKeys(key + str + '\\', variable, value);
599     if (!result)
600       return result;
601   }
602 
603   return PString::Empty();
604 }
605 
606 
BindInterface(const PString & interfaceName)607 bool PWin32PacketVxD::BindInterface(const PString & interfaceName)
608 {
609   BYTE buf[20];
610   DWORD rxsize;
611 
612   if (hDriver == INVALID_HANDLE_VALUE) {
613     hDriver = CreateFile("\\\\.\\" PACKET_VXD_NAME ".VXD",
614                          GENERIC_READ | GENERIC_WRITE,
615                          0,
616                          NULL,
617                          OPEN_EXISTING,
618                          FILE_ATTRIBUTE_NORMAL |
619                              FILE_FLAG_OVERLAPPED |
620                              FILE_FLAG_DELETE_ON_CLOSE,
621                          NULL);
622     if (hDriver == INVALID_HANDLE_VALUE) {
623       dwError = ::GetLastError();
624       return false;
625     }
626 
627 #ifndef USE_VPACKET
628     rxsize = 0;
629     if (!IoControl(IOCTL_EPACKET_VERSION, NULL, 0, buf, sizeof(buf), rxsize)) {
630       dwError = ::GetLastError();
631       return false;
632     }
633 
634     if (rxsize != 2 || buf[0] < 1 || buf[1] < 1) {  // Require driver version 1.1
635       Close();
636       dwError = ERROR_BAD_DRIVER;
637       return false;
638     }
639 #endif
640   }
641 
642   PString devName;
643   PINDEX colon = interfaceName.Find(':');
644   if (colon != P_MAX_INDEX)
645     devName = interfaceName.Left(colon);
646   else
647     devName = interfaceName;
648 
649   rxsize = 0;
650   if (!IoControl(IOCTL_EPACKET_BIND,
651                  (const char *)devName, devName.GetLength()+1,
652                  buf, sizeof(buf), rxsize) || rxsize == 0) {
653     dwError = ::GetLastError();
654     if (dwError == 0)
655       dwError = ERROR_BAD_DRIVER;
656     return false;
657   }
658 
659   // Get a random OID to verify that the driver did actually open
660   if (!QueryOid(OID_GEN_DRIVER_VERSION, 2, buf))
661     return false;
662 
663   dwError = ERROR_SUCCESS;    // Successful, even if may not be bound.
664 
665   PString devKey = SearchRegistryKeys("HKEY_LOCAL_MACHINE\\Enum\\", "Driver", "Net\\" + devName);
666   if (devKey.IsEmpty())
667     return true;
668 
669   RegistryKey bindRegistry(devKey + "Bindings", RegistryKey::ReadOnly);
670   PString binding;
671   PINDEX idx = 0;
672   while (bindRegistry.EnumValue(idx++, binding)) {
673     if (binding.Left(6) *= "MSTCP\\") {
674       RegistryKey mstcpRegistry("HKEY_LOCAL_MACHINE\\Enum\\Network\\" + binding, RegistryKey::ReadOnly);
675       PString str;
676       if (mstcpRegistry.QueryValue("Driver", str))
677         transportBinding.AppendString(SERVICES_REGISTRY_KEY "Class\\" + str);
678     }
679   }
680   return true;
681 }
682 
683 
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)684 bool PWin32PacketVxD::EnumIpAddress(PINDEX idx,
685                                     PIPSocket::Address & addr,
686                                     PIPSocket::Address & net_mask)
687 {
688   if (idx >= transportBinding.GetSize())
689     return false;
690 
691   RegistryKey transportRegistry(transportBinding[idx], RegistryKey::ReadOnly);
692   PString str;
693   if (transportRegistry.QueryValue("IPAddress", str))
694     addr = str;
695   else
696     addr = 0;
697 
698   if (addr != 0) {
699     if (addr.GetVersion() == 6) {
700       net_mask = 0;
701       // Seb: Something to do ?
702     } else {
703       if (transportRegistry.QueryValue("IPMask", str))
704         net_mask = str;
705       else {
706         if (IN_CLASSA(addr))
707           net_mask = "255.0.0.0";
708         else if (IN_CLASSB(addr))
709           net_mask = "255.255.0.0";
710         else if (IN_CLASSC(addr))
711           net_mask = "255.255.255.0";
712         else
713           net_mask = 0;
714       }
715     }
716     return true;
717   }
718 
719   PEthSocket::Address macAddress;
720   if (!QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(macAddress), macAddress.b))
721     return false;
722 
723   PINDEX dhcpCount;
724   for (dhcpCount = 0; dhcpCount < 8; dhcpCount++) {
725     RegistryKey dhcpRegistry(psprintf(SERVICES_REGISTRY_KEY "VxD\\DHCP\\DhcpInfo%02u", dhcpCount),
726                              RegistryKey::ReadOnly);
727     if (dhcpRegistry.QueryValue("DhcpInfo", str)) {
728       struct DhcpInfo {
729         DWORD index;
730         PIPSocket::Address ipAddress;
731         PIPSocket::Address mask;
732         PIPSocket::Address server;
733         PIPSocket::Address anotherAddress;
734         DWORD unknown1;
735         DWORD unknown2;
736         DWORD unknown3;
737         DWORD unknown4;
738         DWORD unknown5;
739         DWORD unknown6;
740         BYTE  unknown7;
741         PEthSocket::Address macAddress;
742       } * dhcpInfo = (DhcpInfo *)(const char *)str;
743       if (dhcpInfo->macAddress == macAddress) {
744         addr = dhcpInfo->ipAddress;
745         net_mask = dhcpInfo->mask;
746         return true;
747       }
748     }
749     else if (dhcpRegistry.QueryValue("HardwareAddress", str) &&
750              str.GetSize() >= sizeof(PEthSocket::Address)) {
751       PEthSocket::Address hardwareAddress;
752       memcpy(&hardwareAddress, (const char *)str, sizeof(hardwareAddress));
753       if (hardwareAddress == macAddress) {
754         if (dhcpRegistry.QueryValue("DhcpIPAddress", str) &&
755             str.GetSize() >= sizeof(addr)) {
756           memcpy(&addr, (const char *)str, sizeof(addr));
757           if (dhcpRegistry.QueryValue("DhcpSubnetMask", str) &&
758               str.GetSize() >= sizeof(net_mask)) {
759             memcpy(&net_mask, (const char *)str, sizeof(net_mask));
760             return true;
761           }
762         }
763       }
764     }
765   }
766 
767   return false;
768 }
769 
770 
BeginRead(void * buf,DWORD size,DWORD & received,PWin32Overlapped & overlap)771 bool PWin32PacketVxD::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
772 {
773   received = 0;
774   if (DeviceIoControl(hDriver, IOCTL_EPACKET_READ,
775                       buf, size, buf, size, &received, &overlap)) {
776     dwError = ERROR_SUCCESS;
777     return true;
778   }
779 
780   dwError = ::GetLastError();
781   return dwError == ERROR_IO_PENDING;
782 }
783 
784 
BeginWrite(const void * buf,DWORD len,PWin32Overlapped & overlap)785 bool PWin32PacketVxD::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
786 {
787   DWORD rxsize = 0;
788   BYTE dummy[2];
789   if (DeviceIoControl(hDriver, IOCTL_EPACKET_WRITE,
790                       (void *)buf, len, dummy, sizeof(dummy), &rxsize, &overlap)) {
791     dwError = ERROR_SUCCESS;
792     return true;
793   }
794 
795   dwError = ::GetLastError();
796   return dwError == ERROR_IO_PENDING;
797 }
798 
799 
800 ///////////////////////////////////////////////////////////////////////////////
801 
RegistryQueryMultiSz(RegistryKey & registry,const PString & variable,PINDEX idx,PString & value)802 static bool RegistryQueryMultiSz(RegistryKey & registry,
803                                  const PString & variable,
804                                  PINDEX idx,
805                                  PString & value)
806 {
807   PString allValues;
808   if (!registry.QueryValue(variable, allValues))
809     return PFalse;
810 
811   const char * ptr = allValues;
812   while (*ptr != '\0' && idx-- > 0)
813     ptr += strlen(ptr)+1;
814 
815   if (*ptr == '\0')
816     return PFalse;
817 
818   value = ptr;
819   return PTrue;
820 }
821 
822 ///////////////////////////////////////////////////////////////////////////////
823 
PWin32PacketSYS()824 PWin32PacketSYS::PWin32PacketSYS()
825 {
826   // Start the packet driver service
827   SC_HANDLE hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
828   if (hManager != NULL) {
829     SC_HANDLE hService = OpenService(hManager, PACKET_SERVICE_NAME, SERVICE_START);
830     if (hService != NULL) {
831       StartService(hService, 0, NULL);
832       dwError = ::GetLastError();
833       CloseServiceHandle(hService);
834     }
835     CloseServiceHandle(hManager);
836   }
837 }
838 
839 
840 static const char PacketDeviceStr[] = "\\Device\\" PACKET_SERVICE_NAME "_";
841 
EnumInterfaces(PINDEX idx,PString & name)842 bool PWin32PacketSYS::EnumInterfaces(PINDEX idx, PString & name)
843 {
844   RegistryKey registry(SERVICES_REGISTRY_KEY PACKET_SERVICE_NAME "\\Linkage",
845                        RegistryKey::ReadOnly);
846   if (!RegistryQueryMultiSz(registry, "Export", idx, name)) {
847     dwError = ERROR_NO_MORE_ITEMS;
848     return false;
849   }
850 
851   if (strncasecmp(name, PacketDeviceStr, sizeof(PacketDeviceStr)-1) == 0)
852     name.Delete(0, sizeof(PacketDeviceStr)-1);
853 
854   return true;
855 }
856 
857 
BindInterface(const PString & interfaceName)858 bool PWin32PacketSYS::BindInterface(const PString & interfaceName)
859 {
860   Close();
861 
862   if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
863                        PACKET_SERVICE_NAME "_" + interfaceName,
864                        PacketDeviceStr + interfaceName)) {
865     dwError = ::GetLastError();
866     return false;
867   }
868 
869   ::SetLastError(0);
870   hDriver = CreateFile("\\\\.\\" PACKET_SERVICE_NAME "_" + interfaceName,
871                        GENERIC_READ | GENERIC_WRITE,
872                        0,
873                        NULL,
874                        CREATE_ALWAYS,
875                        FILE_FLAG_OVERLAPPED,
876                        NULL);
877   if (hDriver == INVALID_HANDLE_VALUE) {
878     dwError = ::GetLastError();
879     return false;
880   }
881 
882   registryKey = SERVICES_REGISTRY_KEY + interfaceName + "\\Parameters\\Tcpip";
883   dwError = ERROR_SUCCESS;
884 
885   return true;
886 }
887 
888 
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)889 bool PWin32PacketSYS::EnumIpAddress(PINDEX idx,
890                                     PIPSocket::Address & addr,
891                                     PIPSocket::Address & net_mask)
892 {
893   PString str;
894   RegistryKey registry(registryKey, RegistryKey::ReadOnly);
895 
896   if (!RegistryQueryMultiSz(registry, "IPAddress", idx, str)) {
897     dwError = ERROR_NO_MORE_ITEMS;
898     return false;
899   }
900   addr = str;
901 
902   if (!RegistryQueryMultiSz(registry, "SubnetMask", idx, str)) {
903     dwError = ERROR_NO_MORE_ITEMS;
904     return false;
905   }
906   net_mask = str;
907 
908   return true;
909 }
910 
911 
BeginRead(void * buf,DWORD size,DWORD & received,PWin32Overlapped & overlap)912 bool PWin32PacketSYS::BeginRead(void * buf, DWORD size, DWORD & received, PWin32Overlapped & overlap)
913 {
914   overlap.Reset();
915   received = 0;
916 
917   if (ReadFile(hDriver, buf, size, &received, &overlap)) {
918     dwError = ERROR_SUCCESS;
919     return true;
920   }
921 
922   return (dwError = ::GetLastError()) == ERROR_IO_PENDING;
923 }
924 
925 
BeginWrite(const void * buf,DWORD len,PWin32Overlapped & overlap)926 bool PWin32PacketSYS::BeginWrite(const void * buf, DWORD len, PWin32Overlapped & overlap)
927 {
928   overlap.Reset();
929   DWORD sent = 0;
930   if (WriteFile(hDriver, buf, len, &sent, &overlap)) {
931     dwError = ERROR_SUCCESS;
932     return true;
933   }
934 
935   dwError = ::GetLastError();
936   return dwError == ERROR_IO_PENDING;
937 }
938 
939 
940 #endif // !_WIN32_WCE
941 
942 ///////////////////////////////////////////////////////////////////////////////
943 
PEthSocket(PINDEX nReadBuffers,PINDEX nWriteBuffers,PINDEX size)944 PEthSocket::PEthSocket(PINDEX nReadBuffers, PINDEX nWriteBuffers, PINDEX size)
945   : readBuffers(min(nReadBuffers, MAXIMUM_WAIT_OBJECTS)),
946     writeBuffers(min(nWriteBuffers, MAXIMUM_WAIT_OBJECTS))
947 {
948   driver = PWin32PacketDriver::Create();
949   PINDEX i;
950   for (i = 0; i < nReadBuffers; i++)
951     readBuffers.SetAt(i, new PWin32PacketBuffer(size));
952   for (i = 0; i < nWriteBuffers; i++)
953     writeBuffers.SetAt(i, new PWin32PacketBuffer(size));
954 
955   filterType = TypeAll;
956 }
957 
958 
~PEthSocket()959 PEthSocket::~PEthSocket()
960 {
961   Close();
962 
963   delete driver;
964 }
965 
966 
OpenSocket()967 PBoolean PEthSocket::OpenSocket()
968 {
969   PAssertAlways(PUnimplementedFunction);
970   return false;
971 }
972 
973 
Close()974 PBoolean PEthSocket::Close()
975 {
976   driver->Close();
977   os_handle = -1;
978   return true;
979 }
980 
981 
GetName() const982 PString PEthSocket::GetName() const
983 {
984   return interfaceName;
985 }
986 
987 
Connect(const PString & newName)988 PBoolean PEthSocket::Connect(const PString & newName)
989 {
990   Close();
991 
992   if (!driver->BindInterface(newName))
993     return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
994 
995   interfaceName = newName;
996   os_handle = 1;
997   return true;
998 }
999 
1000 
EnumInterfaces(PINDEX idx,PString & name)1001 PBoolean PEthSocket::EnumInterfaces(PINDEX idx, PString & name)
1002 {
1003   return driver->EnumInterfaces(idx, name);
1004 }
1005 
1006 
GetAddress(Address & addr)1007 PBoolean PEthSocket::GetAddress(Address & addr)
1008 {
1009   if (driver->QueryOid(OID_802_3_CURRENT_ADDRESS, sizeof(addr), addr.b))
1010     return true;
1011 
1012   return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1013 }
1014 
1015 
EnumIpAddress(PINDEX idx,PIPSocket::Address & addr,PIPSocket::Address & net_mask)1016 PBoolean PEthSocket::EnumIpAddress(PINDEX idx,
1017                                PIPSocket::Address & addr,
1018                                PIPSocket::Address & net_mask)
1019 {
1020   if (IsOpen()) {
1021     if (driver->EnumIpAddress(idx, addr, net_mask))
1022       return true;
1023 
1024     return SetErrorValues(NotFound, ENOENT);
1025   }
1026 
1027   return SetErrorValues(NotOpen, EBADF);
1028 }
1029 
1030 
1031 static const struct {
1032   unsigned pwlib;
1033   DWORD    ndis;
1034 } FilterMasks[] = {
1035   { PEthSocket::FilterDirected,     NDIS_PACKET_TYPE_DIRECTED },
1036   { PEthSocket::FilterMulticast,    NDIS_PACKET_TYPE_MULTICAST },
1037   { PEthSocket::FilterAllMulticast, NDIS_PACKET_TYPE_ALL_MULTICAST },
1038   { PEthSocket::FilterBroadcast,    NDIS_PACKET_TYPE_BROADCAST },
1039   { PEthSocket::FilterPromiscuous,  NDIS_PACKET_TYPE_PROMISCUOUS }
1040 };
1041 
1042 
GetFilter(unsigned & mask,WORD & type)1043 PBoolean PEthSocket::GetFilter(unsigned & mask, WORD & type)
1044 {
1045   if (!IsOpen())
1046     return SetErrorValues(NotOpen, EBADF);
1047 
1048   DWORD filter = 0;
1049   if (!driver->QueryOid(OID_GEN_CURRENT_PACKET_FILTER, filter))
1050     return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1051 
1052   if (filter == 0)
1053     return PEthSocket::FilterDirected;
1054 
1055   mask = 0;
1056   for (PINDEX i = 0; i < PARRAYSIZE(FilterMasks); i++) {
1057     if ((filter&FilterMasks[i].ndis) != 0)
1058       mask |= FilterMasks[i].pwlib;
1059   }
1060 
1061   type = (WORD)filterType;
1062   return true;
1063 }
1064 
1065 
SetFilter(unsigned filter,WORD type)1066 PBoolean PEthSocket::SetFilter(unsigned filter, WORD type)
1067 {
1068   if (!IsOpen())
1069     return SetErrorValues(NotOpen, EBADF);
1070 
1071   DWORD bits = 0;
1072   for (PINDEX i = 0; i < PARRAYSIZE(FilterMasks); i++) {
1073     if ((filter&FilterMasks[i].pwlib) != 0)
1074       bits |= FilterMasks[i].ndis;
1075   }
1076 
1077   if (!driver->SetOid(OID_GEN_CURRENT_PACKET_FILTER, bits))
1078     return SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1079 
1080   filterType = type;
1081   return true;
1082 }
1083 
1084 
GetMedium()1085 PEthSocket::MediumTypes PEthSocket::GetMedium()
1086 {
1087   if (!IsOpen()) {
1088     SetErrorValues(NotOpen, EBADF);
1089     return NumMediumTypes;
1090   }
1091 
1092   DWORD medium = 0xffffffff;
1093   if (!driver->QueryOid(OID_GEN_MEDIA_SUPPORTED, medium) || medium == 0xffffffff) {
1094     SetErrorValues(Miscellaneous, driver->GetLastError()|PWIN32ErrorFlag);
1095     return NumMediumTypes;
1096   }
1097 
1098   static const DWORD MediumValues[NumMediumTypes] = {
1099     0xffffffff, NdisMedium802_3, NdisMediumWan, 0xffffffff
1100   };
1101 
1102   for (int type = Medium802_3; type < NumMediumTypes; type++) {
1103     if (MediumValues[type] == medium)
1104       return (MediumTypes)type;
1105   }
1106 
1107   return MediumUnknown;
1108 }
1109 
1110 
Read(void * data,PINDEX length)1111 PBoolean PEthSocket::Read(void * data, PINDEX length)
1112 {
1113   if (!IsOpen())
1114     return SetErrorValues(NotOpen, EBADF, LastReadError);
1115 
1116   PINDEX idx;
1117   PINDEX numBuffers = readBuffers.GetSize();
1118 
1119   do {
1120     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1121 
1122     for (idx = 0; idx < numBuffers; idx++) {
1123       PWin32PacketBuffer & buffer = readBuffers[idx];
1124       if (buffer.InProgress()) {
1125         if (WaitForSingleObject(buffer.GetEvent(), 0) == WAIT_OBJECT_0)
1126           if (!buffer.ReadComplete(*driver))
1127             return ConvertOSError(-1, LastReadError);
1128       }
1129       else {
1130         if (!buffer.ReadAsync(*driver))
1131           return ConvertOSError(-1, LastReadError);
1132       }
1133 
1134       if (buffer.IsCompleted() && buffer.IsType(filterType)) {
1135         lastReadCount = buffer.GetData(data, length);
1136         return true;
1137       }
1138 
1139       handles[idx] = buffer.GetEvent();
1140     }
1141 
1142     DWORD result;
1143     PINDEX retries = 100;
1144     for (;;) {
1145       result = WaitForMultipleObjects(numBuffers, handles, false, INFINITE);
1146       if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + (DWORD)numBuffers)
1147         break;
1148 
1149       if (::GetLastError() != ERROR_INVALID_HANDLE || retries == 0)
1150         return ConvertOSError(-1, LastReadError);
1151 
1152       retries--;
1153     }
1154 
1155     idx = result - WAIT_OBJECT_0;
1156     if (!readBuffers[idx].ReadComplete(*driver))
1157       return ConvertOSError(-1, LastReadError);
1158 
1159   } while (!readBuffers[idx].IsType(filterType));
1160 
1161   lastReadCount = readBuffers[idx].GetData(data, length);
1162   return true;
1163 }
1164 
1165 
Write(const void * data,PINDEX length)1166 PBoolean PEthSocket::Write(const void * data, PINDEX length)
1167 {
1168   if (!IsOpen())
1169     return SetErrorValues(NotOpen, EBADF, LastWriteError);
1170 
1171   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1172   PINDEX numBuffers = writeBuffers.GetSize();
1173 
1174   PINDEX idx;
1175   for (idx = 0; idx < numBuffers; idx++) {
1176     PWin32PacketBuffer & buffer = writeBuffers[idx];
1177     if (buffer.InProgress()) {
1178       if (WaitForSingleObject(buffer.GetEvent(), 0) == WAIT_OBJECT_0)
1179         if (!buffer.WriteComplete(*driver))
1180           return ConvertOSError(-1, LastWriteError);
1181     }
1182 
1183     if (!buffer.InProgress()) {
1184       lastWriteCount = buffer.PutData(data, length);
1185       return ConvertOSError(buffer.WriteAsync(*driver) ? 0 : -1, LastWriteError);
1186     }
1187 
1188     handles[idx] = buffer.GetEvent();
1189   }
1190 
1191   DWORD result = WaitForMultipleObjects(numBuffers, handles, false, INFINITE);
1192   if (result < WAIT_OBJECT_0 || result >= WAIT_OBJECT_0 + (DWORD) numBuffers)
1193     return ConvertOSError(-1, LastWriteError);
1194 
1195   idx = result - WAIT_OBJECT_0;
1196   if (!writeBuffers[idx].WriteComplete(*driver))
1197     return ConvertOSError(-1, LastWriteError);
1198 
1199   lastWriteCount = writeBuffers[idx].PutData(data, length);
1200   return ConvertOSError(writeBuffers[idx].WriteAsync(*driver) ? 0 : -1, LastWriteError);
1201 }
1202 
1203 
1204 ///////////////////////////////////////////////////////////////////////////////
1205 
PWin32PacketBuffer(PINDEX sz)1206 PWin32PacketBuffer::PWin32PacketBuffer(PINDEX sz)
1207   : PBYTEArray(sz)
1208 {
1209   status = Uninitialised;
1210   count = 0;
1211 }
1212 
1213 
GetData(void * buf,PINDEX size)1214 PINDEX PWin32PacketBuffer::GetData(void * buf, PINDEX size)
1215 {
1216   if (count > (DWORD)size)
1217     count = size;
1218 
1219   memcpy(buf, theArray, count);
1220 
1221   return count;
1222 }
1223 
1224 
PutData(const void * buf,PINDEX length)1225 PINDEX PWin32PacketBuffer::PutData(const void * buf, PINDEX length)
1226 {
1227   count = min(GetSize(), length);
1228 
1229   memcpy(theArray, buf, count);
1230 
1231   return count;
1232 }
1233 
1234 
ReadAsync(PWin32PacketDriver & pkt)1235 PBoolean PWin32PacketBuffer::ReadAsync(PWin32PacketDriver & pkt)
1236 {
1237   if (status == Progressing)
1238     return false;
1239 
1240   status = Uninitialised;
1241   if (!pkt.BeginRead(theArray, GetSize(), count, overlap))
1242     return false;
1243 
1244   if (pkt.GetLastError() == ERROR_SUCCESS)
1245     status = Completed;
1246   else
1247     status = Progressing;
1248   return true;
1249 }
1250 
1251 
ReadComplete(PWin32PacketDriver & pkt)1252 PBoolean PWin32PacketBuffer::ReadComplete(PWin32PacketDriver & pkt)
1253 {
1254   if (status != Progressing)
1255     return status == Completed;
1256 
1257   if (!pkt.CompleteIO(count, overlap)) {
1258     status = Uninitialised;
1259     return false;
1260   }
1261 
1262   status = Completed;
1263   return true;
1264 }
1265 
1266 
WriteAsync(PWin32PacketDriver & pkt)1267 PBoolean PWin32PacketBuffer::WriteAsync(PWin32PacketDriver & pkt)
1268 {
1269   if (status == Progressing)
1270     return false;
1271 
1272   status = Uninitialised;
1273   if (!pkt.BeginWrite(theArray, count, overlap))
1274     return false;
1275 
1276   if (pkt.GetLastError() == ERROR_SUCCESS)
1277     status = Completed;
1278   else
1279     status = Progressing;
1280   return true;
1281 }
1282 
1283 
WriteComplete(PWin32PacketDriver & pkt)1284 PBoolean PWin32PacketBuffer::WriteComplete(PWin32PacketDriver & pkt)
1285 {
1286   if (status != Progressing)
1287     return status == Completed;
1288 
1289   DWORD dummy;
1290   if (pkt.CompleteIO(dummy, overlap)) {
1291     status = Completed;
1292     return true;
1293   }
1294 
1295   status = Uninitialised;
1296   return false;
1297 }
1298 
1299 
IsType(WORD filterType) const1300 PBoolean PWin32PacketBuffer::IsType(WORD filterType) const
1301 {
1302   if (filterType == PEthSocket::TypeAll)
1303     return true;
1304 
1305   const PEthSocket::Frame * frame = (const PEthSocket::Frame *)theArray;
1306 
1307   WORD len_or_type = ntohs(frame->snap.length);
1308   if (len_or_type > sizeof(*frame))
1309     return len_or_type == filterType;
1310 
1311   if (frame->snap.dsap == 0xaa && frame->snap.ssap == 0xaa)
1312     return ntohs(frame->snap.type) == filterType;   // SNAP header
1313 
1314   if (frame->snap.dsap == 0xff && frame->snap.ssap == 0xff)
1315     return PEthSocket::TypeIPX == filterType;   // Special case for Novell netware's stuffed up 802.3
1316 
1317   if (frame->snap.dsap == 0xe0 && frame->snap.ssap == 0xe0)
1318     return PEthSocket::TypeIPX == filterType;   // Special case for Novell netware's 802.2
1319 
1320   return frame->snap.dsap == filterType;    // A pure 802.2 protocol id
1321 }
1322 
1323 ///////////////////////////////////////////////////////////////////////////////
1324 
1325 class PIPRouteTable
1326 {
1327 public:
PIPRouteTable()1328   PIPRouteTable()
1329   {
1330     ULONG size = 0;
1331     DWORD error = GetIpForwardTable(NULL, &size, TRUE);
1332     if (error == ERROR_INSUFFICIENT_BUFFER && buffer.SetSize(size))
1333       error = GetIpForwardTable((MIB_IPFORWARDTABLE *)buffer.GetPointer(), &size, TRUE);
1334     if (error != NO_ERROR) {
1335       buffer.SetSize(0);
1336       buffer.SetSize(sizeof(MIB_IPFORWARDTABLE)); // So ->dwNumEntries returns zero
1337     }
1338   }
1339 
Ptr() const1340   const MIB_IPFORWARDTABLE * Ptr() const { return (const MIB_IPFORWARDTABLE *)(const BYTE *)buffer; }
operator ->() const1341   const MIB_IPFORWARDTABLE * operator->() const { return  Ptr(); }
operator *() const1342   const MIB_IPFORWARDTABLE & operator *() const { return *Ptr(); }
operator const MIB_IPFORWARDTABLE*() const1343   operator const MIB_IPFORWARDTABLE *  () const { return  Ptr(); }
1344 
1345   private:
1346     PBYTEArray buffer;
1347 };
1348 
1349 
1350 class PIPInterfaceAddressTable
1351 {
1352 public:
PIPInterfaceAddressTable()1353   PIPInterfaceAddressTable()
1354   {
1355     ULONG size = 0;
1356     DWORD error = GetIpAddrTable(NULL, &size, FALSE);
1357     if (error == ERROR_INSUFFICIENT_BUFFER && buffer.SetSize(size))
1358       error = GetIpAddrTable((MIB_IPADDRTABLE *)buffer.GetPointer(), &size, FALSE);
1359     if (error != NO_ERROR) {
1360       buffer.SetSize(0);
1361       buffer.SetSize(sizeof(MIB_IPADDRTABLE)); // So ->NumAdapters returns zero
1362     }
1363   }
1364 
Ptr() const1365   const MIB_IPADDRTABLE * Ptr() const { return (const MIB_IPADDRTABLE *)(const BYTE *)buffer; }
operator ->() const1366   const MIB_IPADDRTABLE * operator->() const { return  Ptr(); }
operator *() const1367   const MIB_IPADDRTABLE & operator *() const { return *Ptr(); }
operator const MIB_IPADDRTABLE*() const1368   operator const MIB_IPADDRTABLE *  () const { return  Ptr(); }
1369 
1370   private:
1371     PBYTEArray buffer;
1372 };
1373 
1374 
1375 #if IPv6_ENABLED
1376 class PIPAdaptersAddressTable
1377 {
1378 public:
1379 
PIPAdaptersAddressTable(DWORD dwFlags=GAA_FLAG_INCLUDE_PREFIX|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_MULTICAST)1380   PIPAdaptersAddressTable(DWORD dwFlags = GAA_FLAG_INCLUDE_PREFIX
1381                                         | GAA_FLAG_SKIP_ANYCAST
1382                                         | GAA_FLAG_SKIP_DNS_SERVER
1383                                         | GAA_FLAG_SKIP_MULTICAST)
1384   {
1385     ULONG size = 0;
1386     DWORD error = GetAdaptersAddresses(AF_UNSPEC, dwFlags, NULL, NULL, &size);
1387     if (buffer.SetSize(size))
1388       error = GetAdaptersAddresses(AF_UNSPEC, dwFlags, NULL, (IP_ADAPTER_ADDRESSES *)buffer.GetPointer(), &size);
1389 
1390     if (error != NO_ERROR) {
1391       buffer.SetSize(0);
1392       buffer.SetSize(sizeof(IP_ADAPTER_ADDRESSES)); // So ->NumAdapters returns zero
1393     }
1394   }
1395 
Ptr() const1396   const IP_ADAPTER_ADDRESSES * Ptr() const { return  (const IP_ADAPTER_ADDRESSES *)(const BYTE *)buffer; }
operator ->() const1397   const IP_ADAPTER_ADDRESSES * operator->() const { return  Ptr(); }
operator *() const1398   const IP_ADAPTER_ADDRESSES & operator *() const { return *Ptr(); }
operator const IP_ADAPTER_ADDRESSES*() const1399   operator const IP_ADAPTER_ADDRESSES *  () const { return  Ptr(); }
1400 
1401 private:
1402   PBYTEArray buffer;
1403 };
1404 
1405 
1406 #include <tchar.h>
1407 
1408 class PIPRouteTableIPv6 : public PIPRouteTable
1409 {
1410 public:
1411 
PIPRouteTableIPv6()1412   PIPRouteTableIPv6()
1413   {
1414     buffer.SetSize(sizeof(MIB_IPFORWARD_TABLE2)); // So ->NumEntries returns zero
1415 
1416     HINSTANCE hInst = LoadLibrary(_T("iphlpapi.dll"));
1417     if (hInst != NULL) {
1418       GETIPFORWARDTABLE2 pfGetIpForwardTable2 = (GETIPFORWARDTABLE2)GetProcAddress(hInst, _T("GetIpForwardTable2"));
1419       FREEMIBTABLE pfFreeMibTable = (FREEMIBTABLE)GetProcAddress(hInst, _T("FreeMibTable"));
1420       if (pfGetIpForwardTable2 != NULL && pfFreeMibTable != NULL) {
1421         PMIB_IPFORWARD_TABLE2 pt = NULL;
1422         DWORD dwError = (*pfGetIpForwardTable2)(AF_UNSPEC, &pt);
1423         if (dwError == NO_ERROR) {
1424           buffer.SetSize(pt->NumEntries * sizeof(MIB_IPFORWARD_ROW2));
1425           memcpy(buffer.GetPointer(), pt, buffer.GetSize());
1426           (*pfFreeMibTable)(pt);
1427         }
1428       }
1429       FreeLibrary(hInst);
1430     }
1431   }
1432 
Ptr() const1433   const MIB_IPFORWARD_TABLE2 * Ptr() const { return  (const MIB_IPFORWARD_TABLE2 *)(const BYTE *)buffer; }
operator ->() const1434   const MIB_IPFORWARD_TABLE2 * operator->() const { return  Ptr(); }
operator *() const1435   const MIB_IPFORWARD_TABLE2 & operator *() const { return *Ptr(); }
operator const MIB_IPFORWARD_TABLE2*() const1436   operator const MIB_IPFORWARD_TABLE2 *  () const { return  Ptr(); }
1437 
1438 
ValidateAddress(DWORD ifIndex,LPSOCKADDR lpSockAddr)1439   bool ValidateAddress(DWORD ifIndex, LPSOCKADDR lpSockAddr)
1440   {
1441     int numEntries = Ptr()->NumEntries;
1442     if (numEntries == 0)
1443       return true;
1444 
1445     if (lpSockAddr == NULL)
1446       return false;
1447 
1448     const MIB_IPFORWARD_ROW2 * row = Ptr()->Table;
1449     for (int i = 0; i < numEntries; i++, row++) {
1450       if (row->InterfaceIndex == ifIndex &&
1451           row->DestinationPrefix.Prefix.si_family == lpSockAddr->sa_family) {
1452         switch (lpSockAddr->sa_family) {
1453           case AF_INET :
1454             if (row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == ((sockaddr_in *)lpSockAddr)->sin_addr.S_un.S_addr)
1455               return true;
1456             break;
1457 
1458           case AF_INET6 :
1459             if (memcmp(row->DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,
1460                 ((sockaddr_in6 *)lpSockAddr)->sin6_addr.u.Byte, sizeof(in6_addr)) == 0)
1461               return true;
1462         }
1463       }
1464     }
1465 
1466     return false;
1467   }
1468 
1469 private:
1470   PBYTEArray buffer;
1471 };
1472 #endif // IPv6_ENABLED
1473 
1474 
1475 ///////////////////////////////////////////////////////////////////////////////
1476 
GetGatewayAddress(Address & addr,int version)1477 PBoolean PIPSocket::GetGatewayAddress(Address & addr, int version)
1478 {
1479   if (version == 6) {
1480 #if IPv6_ENABLED
1481     PIPRouteTableIPv6 routes;
1482     int numEntries = routes->NumEntries;
1483     if (numEntries > 0) {
1484       const MIB_IPFORWARD_ROW2 * row = routes->Table;
1485       for (int i = 0; i < numEntries; i++, row++) {
1486         if (row->NextHop.si_family == AF_INET6) {
1487           PIPSocket::Address hop(row->NextHop.Ipv6.sin6_addr);
1488           if (hop.IsValid()) {
1489             addr = hop;
1490             return true;
1491           }
1492         }
1493       }
1494     }
1495 #endif
1496     return false;
1497   }
1498 
1499   PIPRouteTable routes;
1500   for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1501     if (routes->table[i].dwForwardMask == 0) {
1502       addr = routes->table[i].dwForwardNextHop;
1503       return true;
1504     }
1505   }
1506   return false;
1507 }
1508 
1509 
GetGatewayInterface(int version)1510 PString PIPSocket::GetGatewayInterface(int version)
1511 {
1512   if (version == 6) {
1513 #if IPv6_ENABLED
1514     PIPRouteTableIPv6 routes;
1515     int numEntries = routes->NumEntries;
1516     if (numEntries > 0) {
1517       const MIB_IPFORWARD_ROW2 * row = routes->Table;
1518       for (int i = 0; i < numEntries; i++, row++) {
1519         if (row->NextHop.si_family == AF_INET6 && PIPSocket::Address(row->NextHop.Ipv6.sin6_addr).IsValid()) {
1520           PIPAdaptersAddressTable adapters;
1521           for (const IP_ADAPTER_ADDRESSES * adapter = &*adapters; adapter != NULL; adapter = adapter->Next) {
1522             if (adapter->IfIndex == row->InterfaceIndex)
1523               return adapter->Description;
1524           }
1525         }
1526       }
1527     }
1528 #endif
1529     return PString::Empty();
1530   }
1531 
1532   PIPRouteTable routes;
1533   for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1534     if (routes->table[i].dwForwardMask == 0) {
1535       MIB_IFROW info;
1536       info.dwIndex = routes->table[i].dwForwardIfIndex;
1537       if (GetIfEntry(&info) == NO_ERROR)
1538         return PString((const char *)info.bDescr, info.dwDescrLen);
1539     }
1540   }
1541   return PString::Empty();
1542 }
1543 
1544 
GetGatewayInterfaceAddress(int version)1545 PIPSocket::Address PIPSocket::GetGatewayInterfaceAddress(int version)
1546 {
1547   if (version == 6) {
1548 #if IPv6_ENABLED
1549     PIPRouteTableIPv6 routes;
1550     if (routes->NumEntries > 0) {
1551       PIPAdaptersAddressTable interfaces;
1552 
1553       for (const IP_ADAPTER_ADDRESSES * adapter = &*interfaces; adapter != NULL; adapter = adapter->Next) {
1554         for (PIP_ADAPTER_UNICAST_ADDRESS unicast = adapter->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) {
1555           if (unicast->Address.lpSockaddr->sa_family != AF_INET6)
1556             continue;
1557 
1558           PIPSocket::Address ip(((sockaddr_in6 *)unicast->Address.lpSockaddr)->sin6_addr);
1559 
1560           if (routes->NumEntries == 0)
1561             return ip;
1562 
1563           // Check if local-link addresses supported (scope_id != 0)
1564           if ((PIPSocket::GetDefaultV6ScopeId() || (ip[0] != 0xFE && ip[1] != 0x80))
1565               &&
1566               routes.ValidateAddress(adapter->IfIndex, unicast->Address.lpSockaddr))
1567             return ip;
1568         }
1569       }
1570     }
1571 #else
1572     return GetDefaultIpAny();
1573 #endif
1574   }
1575 
1576   PIPRouteTable routes;
1577   for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1578     if (routes->table[i].dwForwardMask == 0) {
1579       PIPInterfaceAddressTable interfaces;
1580       for (unsigned j = 0; j < interfaces->dwNumEntries; ++j) {
1581         if (interfaces->table[j].dwIndex == routes->table[i].dwForwardIfIndex)
1582           return interfaces->table[j].dwAddr;
1583       }
1584     }
1585   }
1586 
1587   return GetDefaultIpAny();
1588 }
1589 
1590 
GetRouteTable(RouteTable & table)1591 PBoolean PIPSocket::GetRouteTable(RouteTable & table)
1592 {
1593   PIPRouteTable routes;
1594 
1595   if (!table.SetSize(routes->dwNumEntries))
1596     return false;
1597 
1598   if (table.IsEmpty())
1599     return false;
1600 
1601   for (unsigned i = 0; i < routes->dwNumEntries; ++i) {
1602     RouteEntry * entry = new RouteEntry(routes->table[i].dwForwardDest);
1603     entry->net_mask = routes->table[i].dwForwardMask;
1604     entry->destination = routes->table[i].dwForwardNextHop;
1605     entry->metric = routes->table[i].dwForwardMetric1;
1606 
1607     MIB_IFROW info;
1608     info.dwIndex = routes->table[i].dwForwardIfIndex;
1609     if (GetIfEntry(&info) == NO_ERROR)
1610       entry->interfaceName = PString((const char *)info.bDescr, info.dwDescrLen);
1611     table.SetAt(i, entry);
1612   }
1613 
1614   return true;
1615 }
1616 
1617 
1618 #ifdef _MSC_VER
1619 #pragma optimize("g", off)
1620 #endif
1621 
1622 class Win32RouteTableDetector : public PIPSocket::RouteTableDetector
1623 {
1624     PDynaLink  m_dll;
1625     BOOL    (WINAPI * m_pCancelIPChangeNotify )(LPOVERLAPPED);
1626     HANDLE     m_hCancel;
1627 
1628   public:
Win32RouteTableDetector()1629     Win32RouteTableDetector()
1630       : m_dll("iphlpapi.dll")
1631       , m_hCancel(CreateEvent(NULL, TRUE, FALSE, NULL))
1632     {
1633       if (!m_dll.GetFunction("CancelIPChangeNotify", (PDynaLink::Function&)m_pCancelIPChangeNotify))
1634         m_pCancelIPChangeNotify = NULL;
1635     }
1636 
~Win32RouteTableDetector()1637     ~Win32RouteTableDetector()
1638     {
1639       if (m_hCancel != NULL)
1640         CloseHandle(m_hCancel);
1641     }
1642 
Wait(const PTimeInterval & timeout)1643     virtual bool Wait(const PTimeInterval & timeout)
1644     {
1645       HANDLE hNotify = NULL;
1646       OVERLAPPED overlap;
1647 
1648       if (m_pCancelIPChangeNotify != NULL) {
1649         memset(&overlap, 0, sizeof(overlap));
1650         DWORD error = NotifyAddrChange(&hNotify, &overlap);
1651         if (error != ERROR_IO_PENDING) {
1652           PTRACE(1, "PTlib\tCould not get network interface change notification: error=" << error);
1653           hNotify = NULL;
1654         }
1655       }
1656 
1657       if (hNotify == NULL)
1658         return WaitForSingleObject(m_hCancel, timeout.GetInterval()) == WAIT_TIMEOUT;
1659 
1660       HANDLE handles[2];
1661       handles[0] = hNotify;
1662       handles[1] = m_hCancel;
1663       switch (WaitForMultipleObjects(2, handles, false, INFINITE)) {
1664         case WAIT_OBJECT_0 :
1665           return true;
1666 
1667         case WAIT_OBJECT_0+1 :
1668           if (m_pCancelIPChangeNotify != NULL)
1669             m_pCancelIPChangeNotify(&overlap);
1670           // Do next case
1671 
1672         default :
1673           return false;
1674       }
1675     }
1676 
Cancel()1677     virtual void Cancel()
1678     {
1679       SetEvent(m_hCancel);
1680     }
1681 };
1682 
1683 #ifdef _MSC_VER
1684 #pragma optimize("", on)
1685 #endif
1686 
1687 
CreateRouteTableDetector()1688 PIPSocket::RouteTableDetector * PIPSocket::CreateRouteTableDetector()
1689 {
1690   return new Win32RouteTableDetector();
1691 }
1692 
1693 
GetRouteAddress(PIPSocket::Address remoteAddress)1694 PIPSocket::Address PIPSocket::GetRouteAddress(PIPSocket::Address remoteAddress)
1695 {
1696   DWORD best;
1697   if (GetBestInterface(remoteAddress, &best) == NO_ERROR) {
1698     PIPInterfaceAddressTable interfaces;
1699     for (unsigned j = 0; j < interfaces->dwNumEntries; ++j) {
1700       if (interfaces->table[j].dwIndex == best)
1701         return interfaces->table[j].dwAddr;
1702     }
1703   }
1704   return GetDefaultIpAny();
1705 }
1706 
1707 
AsNumeric(PIPSocket::Address addr)1708 unsigned PIPSocket::AsNumeric(PIPSocket::Address addr)
1709 {
1710   return ((addr.Byte1() << 24) | (addr.Byte2()  << 16) | (addr.Byte3()  << 8) | addr.Byte4());
1711 }
1712 
IsAddressReachable(PIPSocket::Address localIP,PIPSocket::Address localMask,PIPSocket::Address remoteIP)1713 PBoolean PIPSocket::IsAddressReachable(PIPSocket::Address localIP,
1714                                        PIPSocket::Address localMask,
1715                                        PIPSocket::Address remoteIP)
1716 {
1717   BYTE t = 255;
1718   int t1=t,t2=t,t3 =t,t4=t;
1719   int b1=0,b2=0,b3=0,b4=0;
1720 
1721   if ((int)localMask.Byte1() > 0) {
1722     t1 = localIP.Byte1() + (t - localMask.Byte1());
1723     b1 = localIP.Byte1();
1724   }
1725 
1726   if ((int)localMask.Byte2() > 0) {
1727     t2 = localIP.Byte2() + (t - localMask.Byte2());
1728     b2 = localIP.Byte2();
1729   }
1730 
1731   if ((int)localMask.Byte3() > 0) {
1732     t3 = localIP.Byte3() + (t - localMask.Byte3());
1733     b3 = localIP.Byte3();
1734   }
1735 
1736   if ((int)localMask.Byte4() > 0) {
1737     t4 = localIP.Byte4() + (t - localMask.Byte4());
1738     b4 = localIP.Byte4();
1739   }
1740 
1741   Address lt = Address((BYTE)t1,(BYTE)t2,(BYTE)t3,(BYTE)t4);
1742   Address lb = Address((BYTE)b1,(BYTE)b2,(BYTE)b3,(BYTE)b4);
1743 
1744   return AsNumeric(remoteIP) > AsNumeric(lb) && AsNumeric(lt) > AsNumeric(remoteIP);
1745 }
1746 
1747 
GetInterface(PIPSocket::Address addr)1748 PString PIPSocket::GetInterface(PIPSocket::Address addr)
1749 {
1750   PIPInterfaceAddressTable byAddress;
1751   for (unsigned i = 0; i < byAddress->dwNumEntries; ++i) {
1752     if (addr == byAddress->table[i].dwAddr) {
1753       MIB_IFROW info;
1754       info.dwIndex = byAddress->table[i].dwIndex;
1755       if (GetIfEntry(&info) == NO_ERROR)
1756         return PString((const char *)info.bDescr, info.dwDescrLen);
1757     }
1758   }
1759 
1760   return PString::Empty();
1761 }
1762 
1763 
GetInterfaceTable(InterfaceTable & table,PBoolean includeDown)1764 PBoolean PIPSocket::GetInterfaceTable(InterfaceTable & table, PBoolean includeDown)
1765 {
1766 #if IPv6_ENABLED
1767   // Adding IPv6 addresses
1768   PIPRouteTableIPv6 routes;
1769   PIPAdaptersAddressTable interfaces;
1770   PIPInterfaceAddressTable byAddress;
1771 
1772   PINDEX count = 0; // address count
1773 
1774   if (!table.SetSize(0))
1775     return false;
1776 
1777   for (const IP_ADAPTER_ADDRESSES * adapter = &*interfaces; adapter != NULL; adapter = adapter->Next) {
1778     if (!includeDown && (adapter->OperStatus != IfOperStatusUp))
1779       continue;
1780 
1781     for (PIP_ADAPTER_UNICAST_ADDRESS unicast = adapter->FirstUnicastAddress; unicast != NULL; unicast = unicast->Next) {
1782       if (!routes.ValidateAddress(adapter->IfIndex, unicast->Address.lpSockaddr))
1783         continue;
1784 
1785       PStringStream macAddr;
1786       macAddr << ::hex << ::setfill('0');
1787       for (unsigned b = 0; b < adapter->PhysicalAddressLength; ++b)
1788         macAddr << setw(2) << (unsigned)adapter->PhysicalAddress[b];
1789 
1790       if (unicast->Address.lpSockaddr->sa_family == AF_INET && PIPSocket::GetDefaultIpAddressFamily() == AF_INET) {
1791         PIPSocket::Address ip(((sockaddr_in *)unicast->Address.lpSockaddr)->sin_addr);
1792 
1793         // Find out address index in byAddress table for the mask
1794         DWORD dwMask = 0L;
1795         for (unsigned i = 0; i < byAddress->dwNumEntries; ++i) {
1796           if (adapter->IfIndex == byAddress->table[i].dwIndex) {
1797             dwMask = byAddress->table[i].dwMask;
1798             break;
1799           }
1800         } // find mask for the address
1801 
1802         table.SetAt(count++, new InterfaceEntry(adapter->Description, ip, dwMask, macAddr));
1803 
1804       } // ipv4
1805       else if (unicast->Address.lpSockaddr->sa_family == AF_INET6 && PIPSocket::GetDefaultIpAddressFamily() == AF_INET6) {
1806         PIPSocket::Address ip(((sockaddr_in6 *)unicast->Address.lpSockaddr)->sin6_addr);
1807 
1808         // Check if local-link addresses supported (scope_id != 0)
1809         if (PIPSocket::GetDefaultV6ScopeId() || (ip[0] != 0xFE && ip[1] != 0x80))
1810           table.SetAt(count++, new InterfaceEntry(adapter->Description, ip, 0L, macAddr));
1811       } // ipv6
1812     }
1813   }
1814 
1815 #else
1816 
1817   PIPInterfaceAddressTable byAddress;
1818 
1819   if (!table.SetSize(byAddress->dwNumEntries))
1820     return false;
1821 
1822   if (table.IsEmpty())
1823     return false;
1824 
1825   PINDEX count = 0;
1826   for (unsigned i = 0; i < byAddress->dwNumEntries; ++i) {
1827     Address addr = byAddress->table[i].dwAddr;
1828 
1829     MIB_IFROW info;
1830     info.dwIndex = byAddress->table[i].dwIndex;
1831     if (GetIfEntry(&info) == NO_ERROR && (includeDown || (addr.IsValid() && info.dwAdminStatus))) {
1832       PStringStream macAddr;
1833       macAddr << ::hex << ::setfill('0');
1834       for (unsigned b = 0; b < info.dwPhysAddrLen; ++b)
1835         macAddr << setw(2) << (unsigned)info.bPhysAddr[b];
1836 
1837       table.SetAt(count++, new InterfaceEntry(PString((const char *)info.bDescr, info.dwDescrLen),
1838                                               addr,
1839                                               byAddress->table[i].dwMask,
1840                                               macAddr));
1841     }
1842   }
1843 
1844   table.SetSize(count); // May shrink due to "down" interfaces.
1845 
1846 #endif
1847 
1848   return true;
1849 }
1850 
1851 
1852 ///////////////////////////////////////////////////////////////////////////////
1853